1979 size_t myread(void *ptr, size_t size, size_t nmemb, FILE *f) { |
1979 size_t myread(void *ptr, size_t size, size_t nmemb, FILE *f) { |
1980 size_t ret = fread(ptr, size, nmemb, f); |
1980 size_t ret = fread(ptr, size, nmemb, f); |
1981 return ret; |
1981 return ret; |
1982 } |
1982 } |
1983 |
1983 |
|
1984 int gen_random_name(char *buf, size_t len) { |
|
1985 char name_prefix[8]; |
|
1986 memset(name_prefix, 0, 8); |
|
1987 dav_rand_bytes(name_prefix, 8); |
|
1988 char *pre = util_hexstr(name_prefix, 8); |
|
1989 int64_t ts = (int64_t)time(NULL); |
|
1990 int w = snprintf(buf, len, "%s-%"PRId64"\0", pre, ts); |
|
1991 free(pre); |
|
1992 return w >= len; |
|
1993 } |
|
1994 |
|
1995 #define VBEGIN_ERROR_MKCOL 1 |
|
1996 #define VBEGIN_ERROR_MOVE 2 |
|
1997 #define VBEGIN_ERROR_PROPPATCH 3 |
|
1998 #define VBEGIN_ERROR_CHECKOUT 4 |
|
1999 int versioning_begin(SyncDirectory *dir, DavResource *res, int *exists) { |
|
2000 int ret = 0; |
|
2001 |
|
2002 if(dir->versioning->type == VERSIONING_SIMPLE) { |
|
2003 DavResource *history_collection = dav_resource_new( |
|
2004 res->session, |
|
2005 dir->versioning->collection); |
|
2006 |
|
2007 // get the path to the version history collection for this resource |
|
2008 // if propfind fails we just assume that it doesn't exist |
|
2009 // better error handling is done later (sync_put_resource) |
|
2010 // if there is no history collection for this resource, we create a one |
|
2011 |
|
2012 DavPropName prop; |
|
2013 prop.ns = DAV_NS; |
|
2014 prop.name = VERSION_PATH_PROPERTY; |
|
2015 *exists = dav_load_prop(res, &prop, 1); |
|
2016 |
|
2017 char *history_href = NULL; |
|
2018 char *vcol_path = dav_get_string_property_ns(res, DAV_NS, VERSION_PATH_PROPERTY); |
|
2019 if(!vcol_path) { |
|
2020 DavResource *history_res = NULL; |
|
2021 |
|
2022 // create a new collection for version history |
|
2023 // the name is a combination of a random prefix and a timestamp |
|
2024 while(!history_res) { |
|
2025 char history_res_name[128]; |
|
2026 gen_random_name(history_res_name, 128); |
|
2027 |
|
2028 history_res = dav_resource_new_child( |
|
2029 res->session, |
|
2030 history_collection, |
|
2031 history_res_name); |
|
2032 if(dav_exists(history_res)) { |
|
2033 dav_resource_free(history_res); |
|
2034 history_res = NULL; |
|
2035 } |
|
2036 } |
|
2037 |
|
2038 history_res->iscollection = TRUE; |
|
2039 if(dav_create(history_res)) { |
|
2040 dav_resource_free(history_res); |
|
2041 dav_resource_free(history_collection); |
|
2042 return VBEGIN_ERROR_MKCOL; |
|
2043 } |
|
2044 |
|
2045 history_href = strdup(history_res->href); |
|
2046 |
|
2047 dav_resource_free(history_res); |
|
2048 } else { |
|
2049 history_href = vcol_path; |
|
2050 } |
|
2051 |
|
2052 // find a free url and move 'res' to this location |
|
2053 DavResource *version_res = NULL; |
|
2054 while(!version_res) { |
|
2055 char version_name[128]; |
|
2056 gen_random_name(version_name, 128); |
|
2057 |
|
2058 char *href = util_concat_path(history_href, version_name); |
|
2059 version_res = dav_resource_new_href(res->session, href); |
|
2060 free(href); |
|
2061 |
|
2062 char *dest = util_get_url(res->session, version_res->href); |
|
2063 int err = dav_moveto(res, dest, FALSE); |
|
2064 free(dest); |
|
2065 |
|
2066 if(err) { |
|
2067 dav_resource_free(version_res); |
|
2068 version_res = NULL; |
|
2069 if(res->session->error != DAV_PRECONDITION_FAILED) { |
|
2070 ret = VBEGIN_ERROR_MOVE; |
|
2071 break; |
|
2072 } |
|
2073 } |
|
2074 } |
|
2075 |
|
2076 if(!ret) { |
|
2077 dav_set_string_property_ns(version_res, DAV_NS, "origin", res->href); |
|
2078 if(dav_store(version_res)) { |
|
2079 ret = VBEGIN_ERROR_PROPPATCH; |
|
2080 } |
|
2081 dav_resource_free(version_res); |
|
2082 |
|
2083 // we can just set the property here and don't need dav_store |
|
2084 // because sync_put_resource will call dav_store(res) later |
|
2085 dav_set_string_property_ns( |
|
2086 res, |
|
2087 DAV_NS, |
|
2088 VERSION_PATH_PROPERTY, |
|
2089 history_href); |
|
2090 } |
|
2091 |
|
2092 if(vcol_path != history_href) { |
|
2093 free(history_href); |
|
2094 } |
|
2095 |
|
2096 dav_resource_free(history_collection); |
|
2097 } else { |
|
2098 // Delta V is so much easier :) |
|
2099 if(dav_checkout(res)) { |
|
2100 ret = VBEGIN_ERROR_CHECKOUT; |
|
2101 } |
|
2102 } |
|
2103 |
|
2104 return ret; |
|
2105 } |
|
2106 |
|
2107 int versioning_end(SyncDirectory *dir, DavResource *res) { |
|
2108 if(dir->versioning->type == VERSIONING_DELTAV) { |
|
2109 return dav_checkin(res); |
|
2110 } |
|
2111 } |
|
2112 |
1984 int sync_put_resource( |
2113 int sync_put_resource( |
1985 SyncDirectory *dir, |
2114 SyncDirectory *dir, |
1986 DavResource *res, |
2115 DavResource *res, |
1987 LocalResource *local, |
2116 LocalResource *local, |
1988 int *counter) |
2117 int *counter) |
1989 { |
2118 { |
1990 char *local_path = util_concat_path(dir->path, res->path); |
2119 char *local_path = util_concat_path(dir->path, res->path); |
1991 |
2120 |
1992 SYS_STAT s; |
2121 SYS_STAT s; |
1993 if(sys_stat(local_path, &s)) { |
2122 if(sys_stat(local_path, &s)) { |
1994 fprintf(stderr, "cannot stat file: %s\n", local_path); |
2123 fprintf(stderr, "Cannot stat file: %s\n", local_path); |
1995 perror(""); |
2124 perror(""); |
1996 free(local_path); |
2125 free(local_path); |
1997 return -1; |
2126 return -1; |
1998 } |
2127 } |
1999 |
2128 |
2012 DavXmlNode *prop = create_xml_taglist(tags); |
2141 DavXmlNode *prop = create_xml_taglist(tags); |
2013 if(prop) { |
2142 if(prop) { |
2014 dav_set_property_ns(res, DAV_NS, "tags", prop); |
2143 dav_set_property_ns(res, DAV_NS, "tags", prop); |
2015 } |
2144 } |
2016 } |
2145 } |
2017 |
2146 |
|
2147 int exists = dav_exists(res); |
|
2148 if(dir->versioning && dir->versioning->always) { |
|
2149 int err = versioning_begin(dir, res, &exists); |
|
2150 if(err) { |
|
2151 fprintf(stderr, "Cannot store version for resource: %s\n", res->href); |
|
2152 free(local_path); |
|
2153 return -1; |
|
2154 } |
|
2155 } else { |
|
2156 exists = dav_exists(res); |
|
2157 } |
|
2158 |
2018 int ret = -1; |
2159 int ret = -1; |
2019 int created = 0; |
|
2020 for(int i=0;i<=dir->max_retry;i++) { |
2160 for(int i=0;i<=dir->max_retry;i++) { |
2021 if(!created && dav_create(res)) { |
2161 if(!exists && dav_create(res)) { |
2022 continue; |
2162 continue; |
2023 } |
2163 } |
2024 created = 1; |
2164 exists = 1; |
2025 if(dav_store(res)) { |
2165 if(dav_store(res)) { |
2026 continue; |
2166 continue; |
2027 } |
2167 } |
2028 ret = 0; |
2168 ret = 0; |
2029 break; |
2169 break; |
2030 } |
2170 } |
2031 |
2171 |
2032 |
2172 if(dir->versioning && dir->versioning->always) { |
|
2173 if(versioning_end(dir, res)) { |
|
2174 fprintf(stderr, "Cannot checkin resource\n"); |
|
2175 ret = 1; |
|
2176 } |
|
2177 } |
2033 |
2178 |
2034 if(ret == 0) { |
2179 if(ret == 0) { |
2035 (*counter)++; |
2180 (*counter)++; |
2036 |
2181 |
2037 // check contentlength and get new etag |
2182 // check contentlength and get new etag |