X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libatalk%2Fadouble%2Fad_open.c;h=b0eb42350553b2924d2e42e9cbc31a1abcf26691;hb=6f3a5b930085e56f39b415f20db02df98dbecfff;hp=6d9bf8f63d8b8e9948b6363df0a54bea40b8d9b1;hpb=6dcaba1d633e3cfa96243c62ad8399f7e5558c48;p=netatalk.git diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index 6d9bf8f6..b0eb4235 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -1,5 +1,5 @@ /* - * $Id: ad_open.c,v 1.48 2009-10-02 09:32:41 franklahm Exp $ + * $Id: ad_open.c,v 1.68 2010-01-06 14:05:15 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 @@ -575,8 +581,8 @@ static int ad_header_read(struct adouble *ad, struct stat *hst) && (ad->ad_version != AD_VERSION2) #endif /* AD_VERSION == AD_VERSION2 */ )) { - errno = EIO; LOG(log_debug, logtype_default, "ad_open: can't parse AppleDouble header."); + errno = EIO; return -1; } @@ -593,8 +599,8 @@ static int ad_header_read(struct adouble *ad, struct stat *hst) buf += AD_HEADER_LEN; if (len > header_len - AD_HEADER_LEN) { - errno = EIO; LOG(log_debug, logtype_default, "ad_header_read: can't read entry info."); + errno = EIO; return -1; } @@ -605,14 +611,14 @@ static int ad_header_read(struct adouble *ad, struct stat *hst) if (!ad_getentryoff(ad, ADEID_RFORK) || (ad_getentryoff(ad, ADEID_RFORK) > sizeof(ad->ad_data)) ) { - errno = EIO; LOG(log_debug, logtype_default, "ad_header_read: problem with rfork entry offset."); + errno = EIO; return -1; } if (ad_getentryoff(ad, ADEID_RFORK) > header_len) { - errno = EIO; LOG(log_debug, logtype_default, "ad_header_read: can't read in entries."); + errno = EIO; return -1; } @@ -760,35 +766,34 @@ static int ad_header_sfm_read(struct adouble *ad, struct stat *hst) * FIXME: should do something for pathname > MAXPATHLEN */ char * -ad_path( path, adflags ) - const char *path; - int adflags; +ad_path( const char *path, int adflags) { static char pathbuf[ MAXPATHLEN + 1]; - char c, *slash, buf[MAXPATHLEN + 1]; - size_t l; + const char *slash; + size_t l ; - l = strlcpy(buf, path, MAXPATHLEN +1); if ( adflags & ADFLAGS_DIR ) { - strcpy( pathbuf, buf); - if ( *buf != '\0' && l < MAXPATHLEN) { + l = strlcpy( pathbuf, path, sizeof(pathbuf)); + + if ( l && l < MAXPATHLEN) { pathbuf[l++] = '/'; - pathbuf[l] = 0; } - slash = ".Parent"; + strlcpy(pathbuf +l, ".AppleDouble/.Parent", sizeof(pathbuf) -l); } else { - if (NULL != ( slash = strrchr( buf, '/' )) ) { - c = *++slash; - *slash = '\0'; - strcpy( pathbuf, buf); - *slash = c; + if (NULL != ( slash = strrchr( path, '/' )) ) { + slash++; + l = slash - path; + /* XXX we must return NULL here and test in the caller */ + if (l > MAXPATHLEN) + l = MAXPATHLEN; + memcpy( pathbuf, path, l); } else { - pathbuf[ 0 ] = '\0'; - slash = buf; + l = 0; + slash = path; } + l += strlcpy( pathbuf +l, ".AppleDouble/", sizeof(pathbuf) -l); + strlcpy( pathbuf + l, slash, sizeof(pathbuf) -l); } - strlcat( pathbuf, ".AppleDouble/", MAXPATHLEN +1); - strlcat( pathbuf, slash, MAXPATHLEN +1); return( pathbuf ); } @@ -857,9 +862,7 @@ static int ad_mkrf_osx(char *path _U_) * */ char * -ad_path_sfm( path, adflags ) - const char *path; - int adflags; +ad_path_sfm( const char *path, int adflags) { static char pathbuf[ MAXPATHLEN + 1]; char c, *slash, buf[MAXPATHLEN + 1]; @@ -938,41 +941,50 @@ static int ad_mkrf_sfm(char *path) #define DEFMASK 07700 /* be conservative */ char -*ad_dir(path) - const char *path; +*ad_dir(const char *path) { 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; } @@ -1051,9 +1063,7 @@ static int ad_mode_st(const char *path, int *mode, struct stat *stbuf) return access right of path parent directory */ int -ad_mode( path, mode ) - const char *path; - int mode; +ad_mode( const char *path, int mode) { struct stat stbuf; ad_mode_st(path, &mode, &stbuf); @@ -1064,17 +1074,14 @@ ad_mode( path, mode ) * Use mkdir() with mode bits taken from ad_mode(). */ int -ad_mkdir( path, mode ) - const char *path; - int mode; +ad_mkdir( const char *path, int mode) { int ret; int st_invalid; struct stat stbuf; -#ifdef DEBUG - LOG(log_info, logtype_default, "ad_mkdir: Creating directory with mode %d", mode); -#endif /* DEBUG */ + 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 ); @@ -1176,28 +1183,72 @@ 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; } -/* ------------------- - * 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( path, adflags, oflags, mode, ad ) - const char *path; - int adflags, oflags, mode; - struct adouble *ad; +int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble *ad) { struct stat st_dir; struct stat st_meta; @@ -1208,22 +1259,12 @@ int ad_open( path, adflags, oflags, mode, ad ) 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; } else { ad->ad_open_forks = ((ad->ad_data_fork.adf_refcount > 0) ? ATTRBIT_DOPEN : 0); @@ -1258,6 +1299,7 @@ int ad_open( path, adflags, oflags, mode, ad ) /* 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 */ @@ -1299,16 +1341,18 @@ int ad_open( path, adflags, oflags, mode, ad ) 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; + 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 ); if (ad->ad_md->adf_fd < 0 ) { if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) { - hoflags = oflags & ~O_CREAT; + hoflags = oflags & ~(O_CREAT | O_EXCL); ad->ad_md->adf_fd = open( ad_p, hoflags, 0 ); } } @@ -1320,6 +1364,7 @@ int ad_open( path, adflags, oflags, mode, ad ) * 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); @@ -1327,7 +1372,7 @@ int ad_open( path, adflags, oflags, mode, ad ) 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); } @@ -1352,16 +1397,23 @@ int ad_open( path, adflags, oflags, mode, ad ) else { return ad_error(ad, adflags); } - } else if (fstat(ad->ad_md->adf_fd, &st_meta) == 0 && st_meta.st_size == 0) { - /* for 0 length files, treat them as new. */ - ad->ad_md->adf_flags = hoflags| O_TRUNC; } else { ad->ad_md->adf_flags = hoflags; + if (fstat(ad->ad_md->adf_fd, &st_meta) == 0 && st_meta.st_size == 0) { + /* for 0 length files, treat them as new. */ + ad->ad_md->adf_flags |= O_TRUNC; + } + else { + /* we have valid data in st_meta stat structure, reused it + in ad_header_read + */ + pst = &st_meta; + } } 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, @@ -1416,8 +1468,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); @@ -1425,6 +1475,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; @@ -1439,7 +1492,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) { @@ -1452,18 +1505,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; - /* 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) { + /* 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; + + 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)); @@ -1481,25 +1550,13 @@ int ad_metadata(const char *name, int flags, struct adouble *adp) } if (!ret && (ADFLAGS_OPENFORKS & flags)) { - u_int16_t attrbits = adp->ad_open_forks; - /* we need to check if the file is open by another process. it's slow so we only do it if we have to: - it's requested. - we don't already have the answer! */ - - 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; - } - adp->ad_open_forks = attrbits; + adp->ad_open_forks |= ad_openforks(adp, adp->ad_open_forks); } return ret; }