APR_DECLARE(apr_status_t) apr_filepath_get(char **rootpath, apr_int32_t flags, apr_pool_t *p) { char path[APR_PATH_MAX]; char *ptr; /* use getcwdpath to make sure that we get the volume name*/ if (!getcwdpath(path, NULL, 0)) { if (errno == ERANGE) return APR_ENAMETOOLONG; else return errno; } /* Strip off the server name if there is one*/ ptr = strpbrk(path, "\\/:"); if (!ptr) { return APR_ENOENT; } if (*ptr == ':') { ptr = path; } *rootpath = apr_pstrdup(p, ptr); if (!(flags & APR_FILEPATH_NATIVE)) { for (ptr = *rootpath; *ptr; ++ptr) { if (*ptr == '\\') *ptr = '/'; } } return APR_SUCCESS; }
/* * Function: sys_set_ea * * Purpose: set a native EA * * Arguments: * * vol (r) current volume * uname (r) filename * attruname (r) EA name * ibuf (r) buffer with EA content * attrsize (r) length EA in ibuf * oflag (r) link and create flag * * Returns: AFP code: AFP_OK on success or appropiate AFP error code * * Effects: * */ int sys_set_ea(VFS_FUNC_ARGS_EA_SET) { int attr_flag; int ret; attr_flag = 0; if ((oflag & O_CREAT) ) attr_flag |= XATTR_CREATE; else if ((oflag & O_TRUNC) ) attr_flag |= XATTR_REPLACE; if ((oflag & O_NOFOLLOW) ) { ret = sys_lsetxattr(uname, attruname, ibuf, attrsize,attr_flag); } else { ret = sys_setxattr(uname, attruname, ibuf, attrsize, attr_flag); } if (ret == -1) { switch(errno) { case OPEN_NOFOLLOW_ERRNO: /* its a symlink and client requested O_NOFOLLOW */ LOG(log_debug, logtype_afpd, "sys_set_ea(\"%s\", ea:'%s'): symlink with kXAttrNoFollow", uname, attruname); return AFP_OK; case EEXIST: LOG(log_debug, logtype_afpd, "sys_set_ea(\"%s/%s\", ea:'%s'): EA already exists", getcwdpath(), uname, attruname); return AFPERR_EXIST; default: LOG(log_error, logtype_afpd, "sys_set_ea(\"%s/%s\", ea:'%s', size: %u, flags: %s|%s|%s): %s", getcwdpath(), uname, attruname, attrsize, oflag & O_CREAT ? "XATTR_CREATE" : "-", oflag & O_TRUNC ? "XATTR_REPLACE" : "-", oflag & O_NOFOLLOW ? "O_NOFOLLOW" : "-", strerror(errno)); return AFPERR_MISC; } } return AFP_OK; }
APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo, const char *fname, apr_int32_t wanted, apr_pool_t *pool) { struct stat info; int srv; NXPathCtx_t pathCtx = 0; getcwdpath(NULL, &pathCtx, CTX_ACTUAL_CWD); #ifdef APR_HAS_PSA srv = getstat(pathCtx, (char*)fname, &info, ST_STAT_BITS|ST_NAME_BIT); #else srv = cstat(pathCtx, (char*)fname, &info, ST_STAT_BITS|ST_NAME_BIT, pool); #endif errno = srv; if (srv == 0) { finfo->pool = pool; finfo->fname = fname; fill_out_finfo(finfo, &info, wanted); if (wanted & APR_FINFO_LINK) wanted &= ~APR_FINFO_LINK; if (wanted & APR_FINFO_NAME) { finfo->name = apr_pstrdup(pool, info.st_name); finfo->valid |= APR_FINFO_NAME; } return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS; } else { #if !defined(ENOENT) || !defined(ENOTDIR) #error ENOENT || ENOTDIR not defined; please see the #error comments at this line in the source for a workaround. /* * If ENOENT || ENOTDIR is not defined in one of the your OS's * include files, APR cannot report a good reason why the stat() * of the file failed; there are cases where it can fail even though * the file exists. This opens holes in Apache, for example, because * it becomes possible for someone to get a directory listing of a * directory even though there is an index (eg. index.html) file in * it. If you do not have a problem with this, delete the above * #error lines and start the compile again. If you need to do this, * please submit a bug report to http://www.apache.org/bug_report.html * letting us know that you needed to do this. Please be sure to * include the operating system you are using. */ /* WARNING: All errors will be handled as not found */ #if !defined(ENOENT) return APR_ENOENT; #else /* WARNING: All errors but not found will be handled as not directory */ if (errno != ENOENT) return APR_ENOENT; else return errno; #endif #else /* All was defined well, report the usual: */ return errno; #endif } }
/* * Function: sys_set_ea * * Purpose: set a native EA * * Arguments: * * vol (r) current volume * uname (r) filename * attruname (r) EA name * ibuf (r) buffer with EA content * attrsize (r) length EA in ibuf * oflag (r) link and create flag * * Returns: AFP code: AFP_OK on success or appropiate AFP error code * * Effects: * */ int sys_set_ea(VFS_FUNC_ARGS_EA_SET) { int attr_flag; int ret; char *eabuf; /* * Buffer for a copy of the xattr plus one byte in case * AFPVOL_EA_SAMBA is used */ eabuf = malloc(attrsize + 1); if (eabuf == NULL) { return AFPERR_MISC; } memcpy(eabuf, ibuf, attrsize); eabuf[attrsize] = 0; attr_flag = 0; if ((oflag & O_CREAT) ) attr_flag |= XATTR_CREATE; else if ((oflag & O_TRUNC) ) attr_flag |= XATTR_REPLACE; if (vol->v_flags & AFPVOL_EA_SAMBA) { attrsize++; } /* PBaranski fix */ if ( fd != -1) { LOG(log_debug, logtype_afpd, "sys_set_ea(%s): file is already opened", uname); ret = sys_fsetxattr(fd, attruname, eabuf, attrsize, attr_flag); } else { if ((oflag & O_NOFOLLOW) ) { ret = sys_lsetxattr(uname, attruname, eabuf, attrsize,attr_flag); } else { ret = sys_setxattr(uname, attruname, eabuf, attrsize, attr_flag); } } /* PBaranski fix */ if (ret == -1) { switch(errno) { case OPEN_NOFOLLOW_ERRNO: /* its a symlink and client requested O_NOFOLLOW */ LOG(log_debug, logtype_afpd, "sys_set_ea(\"%s\", ea:'%s'): symlink with kXAttrNoFollow", uname, attruname); return AFP_OK; case EEXIST: LOG(log_debug, logtype_afpd, "sys_set_ea(\"%s/%s\", ea:'%s'): EA already exists", getcwdpath(), uname, attruname); return AFPERR_EXIST; case ENOATTR: case ENOENT: if ((attr_flag & XATTR_REPLACE) && (vol->v_obj->afp_version >= 34)) return AFPERR_NOITEM; return AFPERR_MISC; default: LOG(log_debug, logtype_afpd, "sys_set_ea(\"%s/%s\", ea:'%s', size: %u, flags: %s|%s|%s): %s", getcwdpath(), uname, attruname, attrsize, oflag & O_CREAT ? "XATTR_CREATE" : "-", oflag & O_TRUNC ? "XATTR_REPLACE" : "-", oflag & O_NOFOLLOW ? "O_NOFOLLOW" : "-", strerror(errno)); return AFPERR_MISC; } } return AFP_OK; }
/*! * This function performs a CNID db search * * Uses globals c1, c2, the search criteria * * @param vol (r) volume we are searching on ... * @param dir (rw) directory we are starting from ... * @param uname (r) UNIX name of object to search * @param rmatches (r) maximum number of matches we can return * @param pos (r) position we've stopped recently * @param rbuf (w) output buffer * @param nrecs (w) number of matches * @param rsize (w) length of data written to output buffer * @param ext (r) extended search flag */ static int catsearch_db(struct vol *vol, struct dir *dir, const char *uname, int rmatches, uint32_t *pos, char *rbuf, uint32_t *nrecs, int *rsize, int ext) { static char resbuf[DBD_MAX_SRCH_RSLTS * sizeof(cnid_t)]; static uint32_t cur_pos; static int num_matches; int ccr ,r; int result = AFP_OK; struct path path; char *rrbuf = rbuf; char buffer[MAXPATHLEN +2]; uint16_t flags = CONV_TOLOWER; LOG(log_debug, logtype_afpd, "catsearch_db(req pos: %u): {pos: %u, name: %s}", *pos, cur_pos, uname); if (*pos != 0 && *pos != cur_pos) { result = AFPERR_CATCHNG; goto catsearch_end; } if (cur_pos == 0 || *pos == 0) { if (convert_charset(vol->v_volcharset, vol->v_volcharset, vol->v_maccharset, uname, strlen(uname), buffer, MAXPATHLEN, &flags) == (size_t)-1) { LOG(log_error, logtype_afpd, "catsearch_db: conversion error"); result = AFPERR_MISC; goto catsearch_end; } LOG(log_debug, logtype_afpd, "catsearch_db: %s", buffer); if ((num_matches = cnid_find(vol->v_cdb, buffer, strlen(uname), resbuf, sizeof(resbuf))) == -1) { result = AFPERR_MISC; goto catsearch_end; } } while (cur_pos < num_matches) { char *name; cnid_t cnid, did; char resolvebuf[12 + MAXPATHLEN + 1]; struct dir *dir; /* Next CNID to process from buffer */ memcpy(&cnid, resbuf + cur_pos * sizeof(cnid_t), sizeof(cnid_t)); did = cnid; if ((name = cnid_resolve(vol->v_cdb, &did, resolvebuf, 12 + MAXPATHLEN + 1)) == NULL) goto next; LOG(log_debug, logtype_afpd, "catsearch_db: {pos: %u, name:%s, cnid: %u}", cur_pos, name, ntohl(cnid)); if ((dir = dirlookup(vol, did)) == NULL) goto next; if (movecwd(vol, dir) < 0 ) goto next; memset(&path, 0, sizeof(path)); path.u_name = name; path.m_name = utompath(vol, name, cnid, utf8_encoding()); if (of_stat(vol, &path) != 0) { switch (errno) { case EACCES: case ELOOP: goto next; case ENOENT: default: result = AFPERR_MISC; goto catsearch_end; } } /* For files path.d_dir is the parent dir, for dirs its the dir itself */ if (S_ISDIR(path.st.st_mode)) if ((dir = dirlookup(vol, cnid)) == NULL) goto next; path.d_dir = dir; LOG(log_maxdebug, logtype_afpd,"catsearch_db: dir: %s, cwd: %s, name: %s", cfrombstr(dir->d_fullpath), getcwdpath(), path.u_name); /* At last we can check the search criteria */ ccr = crit_check(vol, &path); if ((ccr & 1)) { LOG(log_debug, logtype_afpd,"catsearch_db: match: %s/%s", getcwdpath(), path.u_name); /* bit 1 means that criteria has been met */ r = rslt_add(vol, &path, &rrbuf, ext); if (r == 0) { result = AFPERR_MISC; goto catsearch_end; } *nrecs += r; /* Number of matches limit */ if (--rmatches == 0) goto catsearch_pause; /* Block size limit */ if (rrbuf - rbuf >= 448) goto catsearch_pause; } next: cur_pos++; } /* while */ /* finished */ result = AFPERR_EOF; cur_pos = 0; goto catsearch_end; catsearch_pause: *pos = cur_pos; catsearch_end: /* Exiting catsearch: error condition */ *rsize = rrbuf - rbuf; LOG(log_debug, logtype_afpd, "catsearch_db(req pos: %u): {pos: %u}", *pos, cur_pos); return result; }
/* * * Dispatcher for all incoming file change events * * */ static int register_fce(const char *u_name, int is_dir, int mode) { if (udp_sockets == 0) /* No listeners configured */ return AFP_OK; if (u_name == NULL) return AFPERR_PARAM; static int first_event = FCE_TRUE; /* do some initialization on the fly the first time */ if (first_event) { fce_initialize_history(); } /* handle files which should not cause events (.DS_Store atc. ) */ for (int i = 0; skip_files[i] != NULL; i++) { if (!strcmp( u_name, skip_files[i])) return AFP_OK; } char full_path_buffer[MAXPATHLEN + 1] = {""}; const char *cwd = getcwdpath(); if (mode == FCE_TM_SIZE) { strlcpy(full_path_buffer, u_name, MAXPATHLEN); } else if (!is_dir || mode == FCE_DIR_DELETE) { if (strlen( cwd ) + strlen( u_name) + 1 >= MAXPATHLEN) { LOG(log_error, logtype_afpd, "FCE file name too long: %s/%s", cwd, u_name ); return AFPERR_PARAM; } sprintf( full_path_buffer, "%s/%s", cwd, u_name ); } else { if (strlen( cwd ) >= MAXPATHLEN) { LOG(log_error, logtype_afpd, "FCE directory name too long: %s", cwd); return AFPERR_PARAM; } strcpy( full_path_buffer, cwd); } /* Can we ignore this event based on type or history? */ if (!(mode & FCE_TM_SIZE) && fce_handle_coalescation( full_path_buffer, is_dir, mode )) { LOG(log_debug9, logtype_afpd, "Coalesced fc event <%d> for <%s>", mode, full_path_buffer ); return AFP_OK; } LOG(log_debug9, logtype_afpd, "Detected fc event <%d> for <%s>", mode, full_path_buffer ); /* we do initilization on the fly, no blocking calls in here * (except when using FQDN in broken DNS environment) */ if (first_event == FCE_TRUE) { fce_init_udp(); /* Notify listeners the we start from the beginning */ send_fce_event( "", FCE_CONN_START ); first_event = FCE_FALSE; } /* Handle UDP transport */ send_fce_event( full_path_buffer, mode ); return AFP_OK; }
/* * * Dispatcher for all incoming file change events * * */ static int register_fce(const char *u_name, int is_dir, int mode) { static int first_event = FCE_TRUE; if (udp_sockets == 0) /* No listeners configured */ return AFP_OK; if (u_name == NULL) return AFPERR_PARAM; /* do some initialization on the fly the first time */ if (first_event) { fce_initialize_history(); first_event = FCE_FALSE; } /* handle files which should not cause events (.DS_Store atc. ) */ for (int i = 0; skip_files[i] != NULL; i++) { if (!strcmp( u_name, skip_files[i])) return AFP_OK; } char full_path_buffer[MAXPATHLEN + 1] = {""}; const char *cwd = getcwdpath(); if (mode == FCE_TM_SIZE) { strlcpy(full_path_buffer, u_name, MAXPATHLEN); } else if (!is_dir || mode == FCE_DIR_DELETE) { if (strlen( cwd ) + strlen( u_name) + 1 >= MAXPATHLEN) { LOG(log_error, logtype_afpd, "FCE file name too long: %s/%s", cwd, u_name ); return AFPERR_PARAM; } sprintf( full_path_buffer, "%s/%s", cwd, u_name ); } else { if (strlen( cwd ) >= MAXPATHLEN) { LOG(log_error, logtype_afpd, "FCE directory name too long: %s", cwd); return AFPERR_PARAM; } strcpy( full_path_buffer, cwd); } /* Can we ignore this event based on type or history? */ if (!(mode & FCE_TM_SIZE) && fce_handle_coalescation( full_path_buffer, is_dir, mode )) { LOG(log_debug9, logtype_afpd, "Coalesced fc event <%d> for <%s>", mode, full_path_buffer ); return AFP_OK; } LOG(log_debug9, logtype_afpd, "Detected fc event <%d> for <%s>", mode, full_path_buffer ); if (mode & FCE_FILE_MODIFY) { save_close_event(full_path_buffer); return AFP_OK; } send_fce_event( full_path_buffer, mode ); return AFP_OK; }