2 * Copyright (c) 2012 Frank Lahm
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
17 * Part of Netatalk's AppleDouble implementatation
18 * @sa include/atalk/adouble.h
23 #endif /* HAVE_CONFIG_H */
26 #include <sys/param.h>
30 #include <arpa/inet.h>
32 #include <atalk/logger.h>
33 #include <atalk/adouble.h>
34 #include <atalk/util.h>
35 #include <atalk/unix.h>
37 #include <atalk/bstrlib.h>
38 #include <atalk/bstradd.h>
39 #include <atalk/compat.h>
40 #include <atalk/errchk.h>
41 #include <atalk/volume.h>
45 static char emptyfilad[32] = {0,0,0,0,0,0,0,0,
50 static char emptydirad[32] = {0,0,0,0,0,0,0,0,
55 static int ad_conv_v22ea_hf(const char *path, const struct stat *sp, const struct vol *vol)
61 uint32_t ctime, mtime, afpinfo = 0;
64 LOG(log_debug, logtype_ad,"ad_conv_v22ea_hf(\"%s\"): BEGIN", fullpathname(path));
66 switch (S_IFMT & sp->st_mode) {
75 ad_init_old(&adv2, AD_VERSION2, adea.ad_options);
77 adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0;
79 /* Open and lock adouble:v2 file */
80 EC_ZERO( ad_open(&adv2, path, adflags | ADFLAGS_HF | ADFLAGS_RDWR) );
82 EC_NEG1_LOG( ad_tmplock(&adv2, ADEID_RFORK, ADLOCK_WR | ADLOCK_FILELOCK, 0, 0, 0) );
83 EC_NEG1_LOG( adv2.ad_ops->ad_header_read(path, &adv2, sp) );
85 /* Check if it's a non-empty header */
86 if (S_ISREG(sp->st_mode))
87 emptyad = &emptyfilad[0];
89 emptyad = &emptydirad[0];
91 if (ad_getentrylen(&adv2, ADEID_COMMENT) != 0)
93 if (ad_getentryoff(&adv2, ADEID_FINDERI)
94 && (ad_getentrylen(&adv2, ADEID_FINDERI) == ADEDLEN_FINDERI)
95 && (memcmp(ad_entry(&adv2, ADEID_FINDERI), emptyad, ADEDLEN_FINDERI) != 0))
97 if (ad_getentryoff(&adv2, ADEID_FILEDATESI)) {
98 EC_ZERO_LOG( ad_getdate(&adv2, AD_DATE_CREATE | AD_DATE_UNIX, &ctime) );
99 EC_ZERO_LOG( ad_getdate(&adv2, AD_DATE_MODIFY | AD_DATE_UNIX, &mtime) );
100 if ((ctime != mtime) || (mtime != sp->st_mtime))
103 if (ad_getentryoff(&adv2, ADEID_AFPFILEI)) {
104 if (memcmp(ad_entry(&adv2, ADEID_AFPFILEI), &afpinfo, ADEDLEN_AFPFILEI) != 0)
108 LOG(log_debug, logtype_ad,"ad_conv_v22ea_hf(\"%s\"): default adouble", fullpathname(path), ret);
112 /* Create a adouble:ea meta EA */
113 LOG(log_debug, logtype_ad,"ad_conv_v22ea_hf(\"%s\"): copying adouble", fullpathname(path), ret);
114 EC_ZERO_LOGSTR( ad_open(&adea, path, adflags | ADFLAGS_HF | ADFLAGS_RDWR | ADFLAGS_CREATE),
115 "ad_conv_v22ea_hf(\"%s\"): error creating metadata EA: %s",
116 fullpathname(path), strerror(errno));
117 EC_ZERO_LOG( ad_copy_header(&adea, &adv2) );
121 EC_ZERO_LOG( ad_close(&adv2, ADFLAGS_HF | ADFLAGS_SETSHRMD) );
122 EC_ZERO_LOG( ad_close(&adea, ADFLAGS_HF | ADFLAGS_SETSHRMD) );
123 LOG(log_debug, logtype_ad,"ad_conv_v22ea_hf(\"%s\"): END: %d", fullpathname(path), ret);
127 static int ad_conv_v22ea_rf(const char *path, const struct stat *sp, const struct vol *vol)
133 LOG(log_debug, logtype_ad,"ad_conv_v22ea_rf(\"%s\"): BEGIN", fullpathname(path));
135 switch (S_IFMT & sp->st_mode) {
142 if (S_ISDIR(sp->st_mode))
146 ad_init_old(&adv2, AD_VERSION2, adea.ad_options);
148 /* Open and lock adouble:v2 file */
149 EC_ZERO( ad_open(&adv2, path, ADFLAGS_HF | ADFLAGS_RF | ADFLAGS_RDWR) );
151 if (adv2.ad_rlen > 0) {
152 EC_NEG1_LOG( ad_tmplock(&adv2, ADEID_RFORK, ADLOCK_WR | ADLOCK_FILELOCK, 0, 0, 0) );
154 /* Create a adouble:ea resource fork */
155 EC_ZERO_LOG( ad_open(&adea, path, ADFLAGS_HF | ADFLAGS_RF | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) );
157 EC_ZERO_LOG( copy_fork(ADEID_RFORK, &adea, &adv2) );
158 adea.ad_rlen = adv2.ad_rlen;
160 fchmod(ad_reso_fileno(&adea), sp->st_mode & 0666);
161 fchown(ad_reso_fileno(&adea), sp->st_uid, sp->st_gid);
165 EC_ZERO_LOG( ad_close(&adv2, ADFLAGS_HF | ADFLAGS_RF) );
166 EC_ZERO_LOG( ad_close(&adea, ADFLAGS_HF | ADFLAGS_RF) );
167 LOG(log_debug, logtype_ad,"ad_conv_v22ea_rf(\"%s\"): END: %d", fullpathname(path), ret);
171 static int ad_conv_v22ea(const char *path, const struct stat *sp, const struct vol *vol)
175 int adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0;
179 if (ad_conv_v22ea_hf(path, sp, vol) != 0)
181 if (ad_conv_v22ea_rf(path, sp, vol) != 0)
185 EC_NULL( adpath = ad_path(path, adflags) );
186 LOG(log_debug, logtype_ad,"ad_conv_v22ea_hf(\"%s\"): deleting adouble:v2 file: \"%s\"",
187 path, fullpathname(adpath));
201 * Remove hexencoded dots and slashes (":2e" and ":2f")
203 static int ad_conv_dehex(const char *path, const struct stat *sp, const struct vol *vol, const char **newpathp)
206 static char buf[MAXPATHLEN];
207 int adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0;
208 bstring newpath = NULL;
209 static bstring str2e = NULL;
210 static bstring str2f = NULL;
211 static bstring strdot = NULL;
212 static bstring strcolon = NULL;
215 str2e = bfromcstr(":2e");
216 str2f = bfromcstr(":2f");
217 strdot = bfromcstr(".");
218 strcolon = bfromcstr(":");
221 LOG(log_debug, logtype_ad,"ad_conv_dehex(\"%s\"): BEGIN", fullpathname(path));
225 if (((strstr(path, ":2e")) == NULL) && ((strstr(path, ":2f")) == NULL) )
228 EC_NULL( newpath = bfromcstr(path) );
230 EC_ZERO( bfindreplace(newpath, str2e, strdot, 0) );
231 EC_ZERO( bfindreplace(newpath, str2f, strcolon, 0) );
234 if (adflags != ADFLAGS_DIR)
235 rename(vol->ad_path(path, 0), vol->ad_path(bdata(newpath), 0));
236 rename(path, bdata(newpath));
239 strlcpy(buf, bdata(newpath), sizeof(buf));
249 * AppleDouble and encoding conversion on the fly
251 * @param path (r) path to file or directory
252 * @param sp (r) stat(path)
253 * @param vol (r) volume handle
254 * @param newpath (w) if encoding changed, new name. Can be NULL.
256 * @returns -1 on internal error, otherwise 0. newpath is NULL if no character conversion was done,
257 * otherwise newpath points to a static string with the converted name
259 int ad_convert(const char *path, const struct stat *sp, const struct vol *vol, const char **newpath)
264 LOG(log_debug, logtype_ad,"ad_convert(\"%s\"): BEGIN", fullpathname(path));
269 if (vol->v_flags & AFPVOL_RO)
272 if ((vol->v_adouble == AD_VERSION_EA) && !(vol->v_flags & AFPVOL_NOV2TOEACONV))
273 EC_ZERO( ad_conv_v22ea(path, sp, vol) );
275 if (vol->v_adouble == AD_VERSION_EA) {
276 EC_ZERO( ad_conv_dehex(path, sp, vol, &p) );
282 LOG(log_debug, logtype_ad,"ad_convert(\"%s\"): END: %d", fullpathname(path), ret);