XDG_PARSED_FILE *XDG_ParseDesktopFile(int fd) { struct stat stats; XDG_PARSED_FILE *parsed = NULL; PARSED_ENTRY **curr_entry; PARSED_GROUP **curr_group; BOOL is_in_group = FALSE; int pos = 0; if (fstat(fd, &stats) == -1) goto failed; parsed = SHAlloc(sizeof(XDG_PARSED_FILE)); if (parsed == NULL) goto failed; parsed->groups = NULL; parsed->head_comments = NULL; parsed->contents = SHAlloc(stats.st_size+1); if (parsed->contents == NULL) goto failed; curr_entry = &parsed->head_comments; curr_group = &parsed->groups; if (read(fd, parsed->contents, stats.st_size) == -1) goto failed; parsed->contents[stats.st_size] = 0; while (pos < stats.st_size) { PARSED_ENTRY statement; int type, size; size = parse_line(parsed->contents + pos, &statement, &type); if (size == -1) goto failed; if (size == 0) break; pos += size; switch (type) { case LINE_GROUP: { PARSED_GROUP *group = SHAlloc(sizeof(PARSED_GROUP)); if (group == NULL) goto failed; is_in_group = TRUE; group->name = statement.name; group->entries = NULL; group->next = NULL; *curr_group = group; curr_group = &group->next; curr_entry = &group->entries; break; } case LINE_ENTRY: if (!is_in_group) goto failed; /* fall through */ case LINE_COMMENT: { PARSED_ENTRY *new_stat = SHAlloc(sizeof(PARSED_ENTRY)); if (new_stat == NULL) goto failed; *new_stat = statement; new_stat->next = NULL; *curr_entry = new_stat; curr_entry = &new_stat->next; break; } } } return parsed; failed: XDG_FreeParsedFile(parsed); return NULL; }
static HRESULT TRASH_GetDetails(const TRASH_BUCKET *bucket, LPCSTR filename, WIN32_FIND_DATAW *data) { LPSTR path = NULL; XDG_PARSED_FILE *parsed = NULL; char *original_file_name = NULL; char *deletion_date = NULL; int fd = -1; struct stat stats; HRESULT ret = S_FALSE; LPWSTR original_dos_name; int suffix_length = lstrlenA(trashinfo_suffix); int filename_length = lstrlenA(filename); int files_length = lstrlenA(bucket->files_dir); int path_length = max(lstrlenA(bucket->info_dir), files_length); path = SHAlloc(path_length + filename_length + 1); if (path == NULL) return E_OUTOFMEMORY; wsprintfA(path, "%s%s", bucket->files_dir, filename); path[path_length + filename_length - suffix_length] = 0; /* remove the '.trashinfo' */ if (lstat(path, &stats) == -1) { ERR("Error accessing data file for trashinfo %s (errno=%d)\n", filename, errno); goto failed; } wsprintfA(path, "%s%s", bucket->info_dir, filename); fd = open(path, O_RDONLY); if (fd == -1) { ERR("Couldn't open trashinfo file %s (errno=%d)\n", path, errno); goto failed; } parsed = XDG_ParseDesktopFile(fd); if (parsed == NULL) { ERR("Parse error in trashinfo file %s\n", path); goto failed; } original_file_name = XDG_GetStringValue(parsed, trashinfo_group, "Path", XDG_URLENCODE); if (original_file_name == NULL) { ERR("No 'Path' entry in trashinfo file\n"); goto failed; } ZeroMemory(data, sizeof(*data)); data->nFileSizeHigh = (DWORD)((LONGLONG)stats.st_size>>32); data->nFileSizeLow = stats.st_size & 0xffffffff; RtlSecondsSince1970ToTime(stats.st_mtime, (LARGE_INTEGER *)&data->ftLastWriteTime); original_dos_name = wine_get_dos_file_name(original_file_name); if (original_dos_name != NULL) { lstrcpynW(data->cFileName, original_dos_name, MAX_PATH); SHFree(original_dos_name); } else { /* show only the file name */ char *file = strrchr(original_file_name, '/'); if (file == NULL) file = original_file_name; MultiByteToWideChar(CP_UNIXCP, 0, file, -1, data->cFileName, MAX_PATH); } deletion_date = XDG_GetStringValue(parsed, trashinfo_group, "DeletionDate", 0); if (deletion_date) { struct tm del_time; time_t del_secs; sscanf(deletion_date, "%d-%d-%dT%d:%d:%d", &del_time.tm_year, &del_time.tm_mon, &del_time.tm_mday, &del_time.tm_hour, &del_time.tm_min, &del_time.tm_sec); del_time.tm_year -= 1900; del_time.tm_mon--; del_time.tm_isdst = -1; del_secs = mktime(&del_time); RtlSecondsSince1970ToTime(del_secs, (LARGE_INTEGER *)&data->ftLastAccessTime); } ret = S_OK; failed: SHFree(path); SHFree(original_file_name); SHFree(deletion_date); if (fd != -1) close(fd); XDG_FreeParsedFile(parsed); return ret; }