X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=blobdiff_plain;f=libatalk%2Fadouble%2Fad_open.c;h=2785cbf17848f8b790f13d5c0d23cc033781b415;hp=2e1d9d856e8e35d6558bcea877451b69accca218;hb=2bf71d3ccf20c072bc67a9d075b6ac8b0798021e;hpb=8403408edab0758e776d6d980f0134105c9fd70a diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index 2e1d9d85..2785cbf1 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -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. @@ -23,8 +23,14 @@ * +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; }