]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/file.c
for .xx files don't set invisible bit if create by netatalk
[netatalk.git] / etc / afpd / file.c
index ab4abf9a6384ba8fbb10d4d0dc157389d40a4a42..6adafe1798d23f29c8d31da16a5a163bc0dac4d5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: file.c,v 1.97 2005-05-14 12:54:52 didg Exp $
+ * $Id: file.c,v 1.104 2006-09-29 09:44:58 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -89,7 +89,7 @@ static int default_type(void *finder)
 }
 
 /* FIXME path : unix or mac name ? (for now it's unix name ) */
-void *get_finderinfo(const char *upath, struct adouble *adp, void *data)
+void *get_finderinfo(const struct vol *vol, const char *upath, struct adouble *adp, void *data)
 {
     struct extmap      *em;
     void                *ad_finder = NULL;
@@ -107,7 +107,7 @@ void *get_finderinfo(const char *upath, struct adouble *adp, void *data)
     else {
         memcpy(data, ufinderi, ADEDLEN_FINDERI);
         chk_ext = 1;
-        if (*upath == '.') { /* make it invisible */
+        if (vol_inv_dots(vol) && *upath == '.') { /* make it invisible */
             u_int16_t ashort;
             
             ashort = htons(FINDERINFO_INVISIBLE);
@@ -227,7 +227,7 @@ u_int32_t aint = 0;
              * for a folder adp is always null
              */
             if (ad_setid(adp, st->st_dev, st->st_ino, aint, did, vol->v_stamp)) {
-                ad_flush(adp, ADFLAGS_HF);
+                ad_flush(adp);
             }
         }
 #endif    
@@ -239,7 +239,7 @@ u_int32_t aint = 0;
 int getmetadata(struct vol *vol,
                  u_int16_t bitmap,
                  struct path *path, struct dir *dir, 
-                 char *buf, int *buflen, struct adouble *adp, int attrbits )
+                 char *buf, int *buflen, struct adouble *adp)
 {
     char               *data, *l_nameoff = NULL, *upath;
     char                *utf_nameoff = NULL;
@@ -284,7 +284,7 @@ int getmetadata(struct vol *vol,
         case FILPBIT_ATTR :
             if ( adp ) {
                 ad_getattr(adp, &ashort);
-            } else if (*upath == '.') {
+            } else if (vol_inv_dots(vol) && *upath == '.') {
                 ashort = htons(ATTRBIT_INVISIBLE);
             } else
                 ashort = 0;
@@ -296,12 +296,10 @@ int getmetadata(struct vol *vol,
             if ((ma.ma_user & AR_UWRITE)) {
                accessmode( upath, &ma, dir , st);
                if (!(ma.ma_user & AR_UWRITE)) {
-                       attrbits |= ATTRBIT_NOWRITE;
+                       ashort |= htons(ATTRBIT_NOWRITE);
                 }
             }
 #endif
-            if (attrbits)
-                ashort = htons(ntohs(ashort) | attrbits);
             memcpy(data, &ashort, sizeof( ashort ));
             data += sizeof( ashort );
             break;
@@ -338,7 +336,7 @@ int getmetadata(struct vol *vol,
             break;
 
         case FILPBIT_FINFO :
-           get_finderinfo(upath, adp, (char *)data);
+           get_finderinfo(vol, upath, adp, (char *)data);
             data += ADEDLEN_FINDERI;
             break;
 
@@ -518,7 +516,6 @@ int getfilparams(struct vol *vol,
     struct adouble     ad, *adp;
     struct ofork        *of;
     char                   *upath;
-    u_int16_t          attrbits = 0;
     int                 opened = 0;
     int rc;    
 
@@ -528,18 +525,18 @@ int getfilparams(struct vol *vol,
 
     opened = PARAM_NEED_ADP(bitmap);
     adp = NULL;
+
     if (opened) {
+        int flags = (bitmap & (1 << FILPBIT_ATTR))?ADFLAGS_OPENFORKS:0;
         upath = path->u_name;
         if ((of = of_findname(path))) {
             adp = of->of_ad;
-           attrbits = ((of->of_ad->ad_df.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
-           attrbits |= ((of->of_ad->ad_hf.adf_refcount > of->of_ad->ad_df.adf_refcount)? ATTRBIT_ROPEN : 0);
         } else {
             ad_init(&ad, vol->v_adouble, vol->v_ad_options);
             adp = &ad;
         }
 
-        if ( ad_metadata( upath, 0, adp) < 0 ) {
+        if ( ad_metadata( upath, flags, adp) < 0 ) {
             switch (errno) {
             case EACCES:
                 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
@@ -554,26 +551,8 @@ int getfilparams(struct vol *vol,
                 break;
             }
         }
-        if (adp) {
-           /* FIXME 
-              we need to check if the file is open by another process.
-              it's slow so we only do it if we have to:
-              - bitmap is requested.
-              - we don't already have the answer!
-           */
-           if ((bitmap & (1 << FILPBIT_ATTR))) {
-                if (!(attrbits & ATTRBIT_ROPEN)) {
-                    attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_ROPEN : 0;
-                    attrbits |= ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_ROPEN : 0;
-                }
-                if (!(attrbits & ATTRBIT_DOPEN)) {
-                    attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_RD) > 0? ATTRBIT_DOPEN : 0;
-                    attrbits |= ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_OPEN_WR) > 0? ATTRBIT_DOPEN : 0;
-                }
-           }
-       }
     }
-    rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp, attrbits);
+    rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp);
     if ( adp ) {
         ad_close_metadata( adp);
     }
@@ -659,7 +638,7 @@ int ibuflen _U_, *rbuflen;
         openf = O_RDWR|O_CREAT|O_EXCL;
     }
 
-    if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
+    if ( ad_open( upath, vol_noadouble(vol)|ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
                   openf, 0666, adp) < 0 ) {
         switch ( errno ) {
         case EROFS:
@@ -670,11 +649,14 @@ int       ibuflen _U_, *rbuflen;
             return( AFPERR_EXIST );
         case EACCES :
             return( AFPERR_ACCESS );
+        case EDQUOT:
+        case ENOSPC :
+            return( AFPERR_DFULL );
         default :
             return( AFPERR_PARAM );
         }
     }
-    if ( ad_hfileno( adp ) == -1 ) {
+    if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */
          /* on noadouble volumes, just creating the data fork is ok */
          if (vol_noadouble(vol)) {
              ad_close( adp, ADFLAGS_DF );
@@ -690,7 +672,7 @@ int ibuflen _U_, *rbuflen;
 
     path = s_path->m_name;
     ad_setname(adp, path);
-    ad_flush( adp, ADFLAGS_DF|ADFLAGS_HF );
+    ad_flush( adp);
     ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
 
 createfile_done:
@@ -995,7 +977,7 @@ setfilparam_done:
     }
 
     if (isad) {
-        ad_flush_metadata( adp);
+        ad_flush( adp);
         ad_close_metadata( adp);
 
     }
@@ -1047,7 +1029,7 @@ struct adouble    *adp;
             * get two files, it's fixable for our process (eg reopen the new file, get the
             * locks, and so on. But it doesn't solve the case with a second process
             */
-           if (adp->ad_df.adf_refcount || adp->ad_hf.adf_refcount) {
+           if (adp->ad_open_forks) {
                /* FIXME  warning in syslog so admin'd know there's a conflict ?*/
                return AFPERR_OLOCK; /* little lie */
            }
@@ -1089,7 +1071,7 @@ struct adouble    *adp;
      */
     if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
         ad_setname(adp, newname);
-        ad_flush( adp, ADFLAGS_HF );
+        ad_flush( adp );
         ad_close( adp, ADFLAGS_HF );
     }
 #ifdef DEBUG
@@ -1323,13 +1305,31 @@ static __inline__ int copy_all(const int dfd, const void *buf,
     return 0;
 }
 
-/* -------------------------- */
-static int copy_fd(int dfd, int sfd)
+/* -------------------------- 
+ * copy only the fork data stream
+*/
+static int copy_fork(int eid, struct adouble *add, struct adouble *ads)
 {
     ssize_t cc;
     int     err = 0;
     char    filebuf[8192];
+    int     sfd, dfd;
     
+    if (eid == ADEID_DFORK) {
+        sfd = ad_data_fileno(ads);
+        dfd = ad_data_fileno(add);
+    }
+    else {
+        sfd = ad_reso_fileno(ads);
+        dfd = ad_reso_fileno(add);
+    }        
+
+    if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET))
+       return -1;
+
+    if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET))
+       return -1;
+       
 #if 0 /* ifdef SENDFILE_FLAVOR_LINUX */
     /* doesn't work With 2.6 FIXME, only check for EBADFD ? */
     off_t   offset = 0;
@@ -1375,8 +1375,9 @@ static int copy_fd(int dfd, int sfd)
 }
 
 /* ----------------------------------
- * if newname is NULL (from directory.c) we don't want to copy ressource fork.
+ * if newname is NULL (from directory.c) we don't want to copy the resource fork.
  * because we are doing it elsewhere.
+ * currently if newname is NULL then adp is NULL. 
  */
 int copyfile(s_vol, d_vol, src, dst, newname, adp )
 const struct vol *s_vol, *d_vol;
@@ -1388,6 +1389,7 @@ struct adouble *adp;
     int                 ret_err = 0;
     int                 adflags;
     int                 noadouble = vol_noadouble(d_vol);
+    int                 stat_result;
     struct stat         st;
     
 #ifdef DEBUG
@@ -1409,12 +1411,19 @@ struct adouble *adp;
         goto done;
     }
 
-    if (ad_hfileno(adp) == -1) {
+    if (ad_meta_fileno(adp) == -1 && ad_reso_fileno(adp) == -1) { /* META / HF */
         /* no resource fork, don't create one for dst file */
         adflags &= ~ADFLAGS_HF;
     }
 
-    if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, 0666, &add) < 0) {
+    stat_result = fstat(ad_data_fileno(adp), &st); /* saving stat exit code, thus saving us on one more stat later on */
+
+    if (stat_result < 0) {           
+      /* unlikely but if fstat fails, the default file mode will be 0666. */
+      st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+    }
+
+    if (ad_open(dst , adflags | noadouble, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
         ret_err = errno;
         ad_close( adp, adflags );
         if (EEXIST != ret_err) {
@@ -1423,45 +1432,36 @@ struct adouble *adp;
         }
         return AFPERR_EXIST;
     }
-    if (ad_hfileno(adp) == -1 || 0 == (err = copy_fd(ad_hfileno(&add), ad_hfileno(adp)))){
+    /* XXX if the source and the dest don't use the same resource type it's broken
+    */
+    if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){
         /* copy the data fork */
-       err = copy_fd(ad_dfileno(&add), ad_dfileno(adp));
+       err = copy_fork(ADEID_DFORK, &add, adp);
     }
 
-    /* Now, reopen destination file */
     if (err < 0) {
        ret_err = errno;
     }
-    ad_close( adp, adflags );
 
-    if (ad_close( &add, adflags ) <0) {
-        deletefile(d_vol, dst, 0);
-        ret_err = errno;
-        goto done;
-    } 
-    else {
-       ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
-       if (ad_open(dst , adflags | noadouble, O_RDWR, 0666, &add) < 0) {
-           ret_err = errno;
-       }
-    }
-
-    if (!ret_err && newname) {
+    if (!ret_err && newname && (adflags & ADFLAGS_HF)) {
+        /* set the new name in the resource fork */
+        ad_copy_header(&add, adp);
         ad_setname(&add, newname);
+        ad_flush( &add );
     }
+    ad_close( adp, adflags );
 
-    ad_flush( &add, adflags );
     if (ad_close( &add, adflags ) <0) {
        ret_err = errno;
-    }
+    } 
+
     if (ret_err) {
         deletefile(d_vol, dst, 0);
     }
-    else if (!stat(src, &st)) {
+    else if (stat_result == 0) {
         /* set dest modification date to src date */
         struct utimbuf ut;
 
-        /* ADS here ? */
        ut.actime = ut.modtime = st.st_mtime;
        utime(dst, &ut);
        /* FIXME netatalk doesn't use resource fork file date
@@ -1502,6 +1502,24 @@ done:
    ad_open always try to open file RDWR first and ad_lock takes care of
    WRITE lock on read only file.
 */
+
+static int check_attrib(struct adouble *adp)
+{
+u_int16_t   bshort = 0;
+
+       ad_getattr(adp, &bshort);
+    /*
+     * Does kFPDeleteInhibitBit (bit 8) set?
+     */
+       if ((bshort & htons(ATTRBIT_NODELETE))) {
+               return AFPERR_OLOCK;
+       }
+    if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) {
+       return AFPERR_BUSY;
+       }
+       return 0;
+}
+
 int deletefile( vol, file, checkAttrib )
 const struct vol      *vol;
 char           *file;
@@ -1517,8 +1535,19 @@ int         checkAttrib;
 
     /* try to open both forks at once */
     adflags = ADFLAGS_DF|ADFLAGS_HF;
-    ad_init(&ad, vol->v_adouble, vol->v_ad_options);  /* OK */
+    if (checkAttrib) {
+        /* was EACCESS error try to get only metadata */
+        ad_init(&ad, vol->v_adouble, vol->v_ad_options);
+        if ( ad_metadata( file , ADFLAGS_OPENFORKS, &ad) == 0 ) {
+            ad_close( &ad, adflags );
+            if ((err = check_attrib(&ad))) {
+               return err;
+            }
+        }
+    }
     while(1) {
+       ad_init(&ad, vol->v_adouble, vol->v_ad_options);  /* OK */
         if ( ad_open( file, adflags, O_RDONLY, 0, &ad ) < 0 ) {
             switch (errno) {
             case ENOENT:
@@ -1540,21 +1569,7 @@ int         checkAttrib;
         }
         break; /* from the while */
     }
-    /*
-     * Does kFPDeleteInhibitBit (bit 8) set?
-     */
-    if (checkAttrib) {
-        u_int16_t   bshort;
-        
-        if ( ad_metadata( file , 0, &ad) == 0 ) {
-            ad_getattr(&ad, &bshort);
-            ad_close_metadata( &ad);
-            if ((bshort & htons(ATTRBIT_NODELETE))) {
-                return  AFPERR_OLOCK;
-            }
-        }
-    }
-    
+
     if (adp && (adflags & ADFLAGS_HF) ) {
         /* FIXME we have a pb here because we want to know if a file is open 
          * there's a 'priority inversion' if you can't open the ressource fork RW
@@ -1711,7 +1726,7 @@ static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
             return 0;
         }
         if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
-            ad_flush_metadata(adp);
+            ad_flush(adp);
         }
         ad_close_metadata(adp);
     }
@@ -1993,7 +2008,8 @@ static struct adouble *find_adouble(struct path *path, struct ofork **of, struct
     }
     else {
         ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
-        if ( !ret && ad_hfileno(adp) != -1 && !(adp->ad_hf.adf_flags & ( O_RDWR | O_WRONLY))) {
+        /* META and HF */
+        if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
             /* from AFP spec.
              * The user must have the Read & Write privilege for both files in order to use this command.
              */
@@ -2196,12 +2212,12 @@ int     ibuflen _U_, *rbuflen;
     /* here we need to reopen if crossdev */
     if (sid && ad_setid(addp, destst.st_dev, destst.st_ino,  sid, sdir->d_did, vol->v_stamp)) 
     {
-       ad_flush( addp, ADFLAGS_HF );
+       ad_flush( addp );
     }
         
     if (did && ad_setid(adsp, srcst.st_dev, srcst.st_ino,  did, curdir->d_did, vol->v_stamp)) 
     {
-       ad_flush( adsp, ADFLAGS_HF );
+       ad_flush( adsp );
     }
 
     /* change perms, src gets dest perm and vice versa */
@@ -2266,10 +2282,10 @@ err_src_to_tmp:
     of_rename(vol, s_of, curdir, temp, sdir, spath);
 
 err_exchangefile:
-    if ( !s_of && adsp && ad_hfileno(adsp) != -1 ) {
+    if ( !s_of && adsp && ad_meta_fileno(adsp) != -1 ) { /* META */
        ad_close(adsp, ADFLAGS_HF);
     }
-    if ( !d_of && addp && ad_hfileno(addp) != -1 ) {
+    if ( !d_of && addp && ad_meta_fileno(addp) != -1 ) {/* META */
        ad_close(addp, ADFLAGS_HF);
     }