/** * Create a file in the debugfs, also create parent directories if needed and * remove the old file if it exists. * * @param path Path to a file to be created. * The path is always treated relative to the Tempesta root * directory in the debugfs (see tfw_debugfs_root). * @param data A pointer to some data which is saved in 'file' and 'inode' * structures. It may be retrieved by any function in @fops as * file->private_data or file->f_inode->i_private (it is copied * into both places). * @param fops A set of functions that handle system calls on the created file. * * * The function creates a file in the debugfs, but does it in a robust way: * - the file is replaced if it already exists * - all parent directories are created if they don't exist * * Returns: An ERR_PTR if the file is not created. */ static struct dentry * create_with_parents(const char *path, void *data, const struct file_operations *fops) { size_t name_size; char *buf, *pos, *component; struct dentry *parent, *child; /* Copy the path to a temporary buffer where it can be modified. */ name_size = strlen(path) + 1; buf = kmalloc(name_size, GFP_KERNEL); BUG_ON(ZERO_OR_NULL_PTR(buf)); strlcpy(buf, path, name_size); /* Eat the leading slash to allow specify either /foo/bar or foo/bar */ pos = buf; if (*pos == '/') ++pos; /* Walk over the path and create non-existing directories. */ parent = tfw_debugfs_root; component = pos; do { if (*pos != '/') continue; *pos = '\0'; child = lookup_file(component, parent); if (!child) { child = debugfs_create_dir(component, parent); BUG_ON(!parent); } parent = child; component = pos + 1; } while (*(++pos)); /* Remove the file if it already exists. */ child = lookup_file(component, parent); if (child) { TFW_DBG("Removing already existing debugfs file: %s\n", path); debugfs_remove(child); } /* Create the actual file. */ child = debugfs_create_file(component, S_IRWXU, parent, data, fops); if (IS_ERR_OR_NULL(child)) { int err = PTR_ERR(child); TFW_WARN("Can't create debugfs file: %s (%d)\n", path, err); } else { TFW_DBG("Created debugfs file: %s\n", path); } kfree(buf); return child; }
static void do_read (void) { char *handle; int length; MateVFSHandle *from_handle; MateVFSResult result; MateVFSFileSize bytes_read; guint8 *data; handle = get_handle (); length = get_int (); if (length < 0) { fprintf (vfserr, "Can't read %d bytes\n", length); return; } from_handle = lookup_file (handle); if (!from_handle) return; data = g_malloc (length); result = mate_vfs_read (from_handle, data, length, &bytes_read); if (show_if_error (result, "read ", handle)) return; ms_ole_dump (data, bytes_read, 0); }
/* * file_writeb: Write binary data (not a line of text) to a file or logfile * * logtype: 0 if 'fd' is an $open() refnum. * 1 if 'fd' is a /window refnum. * 2 if 'fd' is a /log refnum. * fd: A reference number, depending on the type of 'logtype' * stuff: CTCP-ENCODED binary data that should be written to a file */ int file_writeb (int logtype, int fd, char *stuff) { File *ptr; int retval; size_t len = strlen(stuff); if (logtype == 2) /* General logfile */ ptr = NULL /* */; else if (logtype == 1) /* Window logfile */ ptr = lookup_window_logfile(fd); else ptr = lookup_file(fd); if (!ptr || !ptr->elf->fp) return -1; /* XXX This should use transform_string() */ stuff = dequote_it(stuff, &len); retval = fwrite(stuff, 1, len, ptr->elf->fp); new_free(&stuff); if ((fflush(ptr->elf->fp)) == EOF) return -1; return retval; }
static void do_cron(void) { void *buf; void (*job)(void) = NULL; struct file *cur, *target; // If a user can cgc_write to the crond directory, they can execute arbitrary code. list_for_each_entry(struct file, list, &crond->files, cur) { if (cur->is_symlink) { if ((target = lookup_file(&vfs, (char *)cur->contents, 1)) == NULL) continue; } else { target = cur; } if (allocate(target->size, 1, &buf) != 0) continue; cgc_memcpy(buf, target->contents, target->size); job = buf; job(); deallocate(buf, cur->size); } }
/* * file_writeb: Write binary data (not a line of text) to a file or logfile * * logtype: 0 if 'fd' is an $open() refnum. * 1 if 'fd' is a /window refnum. * 2 if 'fd' is a /log refnum. * fd: A reference number, depending on the type of 'logtype' * text: CTCP-ENCODED binary data that should be written to a file */ int file_writeb (int logtype, int fd, char *text) { File * ptr; int retval; char * ret; size_t retlen; if (logtype == 2) /* General logfile */ ptr = NULL /* */; else if (logtype == 1) /* Window logfile */ ptr = lookup_window_logfile(fd); else ptr = lookup_file(fd); if (!ptr || !ptr->elf->fp) return -1; if (!(ret = transform_string_dyn("-CTCP", text, 0, &retlen))) { yell("$writeb(): Could not CTCP dequote [%s]", text); return -1; } retval = fwrite(ret, 1, retlen, ptr->elf->fp); new_free(&ret); if ((fflush(ptr->elf->fp)) == EOF) return -1; return retval; }
static int do_read(void) { int ret = -1; char name[MAX_FILE_NAME_LENGTH + 1]; char *contents, *path; struct file *file; if (read_all(STDIN, name, MAX_FILE_NAME_LENGTH) != MAX_FILE_NAME_LENGTH) return -1; name[MAX_FILE_NAME_LENGTH] = '\0'; if ((path = get_path_from_dir(&vfs, pwd)) == NULL) return -1; if ((path = append_to_path(path, name)) == NULL) goto free_path; if ((file = lookup_file(&vfs, path, 1)) == NULL) goto free_path; if (read_file(&vfs, USER_UID, path, (unsigned char **)&contents) != 0) goto free_path; write_all(STDOUT, contents, file->size); ret = 0; free_path: free(path); return ret; }
static int do_rm(void) { int ret = -1; char name[MAX_FILE_NAME_LENGTH + 1]; char *path; struct file *file; if (read_all(STDIN, name, MAX_FILE_NAME_LENGTH) != MAX_FILE_NAME_LENGTH) return -1; name[MAX_FILE_NAME_LENGTH] = '\0'; if ((path = get_path_from_dir(&vfs, pwd)) == NULL) return -1; if ((path = append_to_path(path, name)) == NULL) goto free_path; if ((file = lookup_file(&vfs, path, 1)) == NULL) goto free_path; if (delete_file(&vfs, USER_UID, file) != 0) goto free_path; ret = 0; free_path: free(path); return ret; }
char * file_readb (int fd, int numb) { File *ptr = lookup_file(fd); if (!ptr) return malloc_strdup(empty_string); else { char * ret; char * blah; blah = (char *)new_malloc(numb+1); if (ptr->elf->fp) { clearerr(ptr->elf->fp); numb = fread(blah, 1, numb, ptr->elf->fp); #ifdef HAVE_LIBARCHIVE } else if (ptr->elf->a) { numb = archive_read_data(ptr->elf->a, blah, numb); #endif } else { /* others */ } if ((ret = transform_string_dyn("+CTCP", blah, numb, NULL))) new_free(&blah); else ret = blah; return ret; } }
void nemo_list_model_file_changed (NemoListModel *model, NemoFile *file, NemoDirectory *directory) { FileEntry *parent_file_entry; GtkTreeIter iter; GtkTreePath *path, *parent_path; GSequenceIter *ptr; int pos_before, pos_after, length, i, old; int *new_order; gboolean has_iter; GSequence *files; ptr = lookup_file (model, file, directory); if (!ptr) { return; } pos_before = g_sequence_iter_get_position (ptr); g_sequence_sort_changed (ptr, nemo_list_model_file_entry_compare_func, model); pos_after = g_sequence_iter_get_position (ptr); if (pos_before != pos_after) { /* The file moved, we need to send rows_reordered */ parent_file_entry = ((FileEntry *)g_sequence_get (ptr))->parent; if (parent_file_entry == NULL) { has_iter = FALSE; parent_path = gtk_tree_path_new (); files = model->details->files; } else { has_iter = TRUE; nemo_list_model_ptr_to_iter (model, parent_file_entry->ptr, &iter); parent_path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); files = parent_file_entry->files; } length = g_sequence_get_length (files); new_order = g_new (int, length); /* Note: new_order[newpos] = oldpos */ for (i = 0, old = 0; i < length; ++i) { if (i == pos_after) { new_order[i] = pos_before; } else { if (old == pos_before) old++; new_order[i] = old++; } } gtk_tree_model_rows_reordered (GTK_TREE_MODEL (model), parent_path, has_iter ? &iter : NULL, new_order); gtk_tree_path_free (parent_path); g_free (new_order); }
time_t ar_member_date (const char *name) { char *arname; char *memname; long int val; ar_parse_name (name, &arname, &memname); /* Make sure we know the modtime of the archive itself because we are likely to be called just before commands to remake a member are run, and they will change the archive itself. But we must be careful not to enter_file the archive itself if it does not exist, because pattern_search assumes that files found in the data base exist or can be made. */ { struct file *arfile; arfile = lookup_file (arname); if (arfile == 0 && file_exists_p (arname)) arfile = enter_file (strcache_add (arname)); if (arfile != 0) (void) f_mtime (arfile, 0); } val = ar_scan (arname, ar_member_date_1, memname); free (arname); return (val <= 0 ? (time_t) -1 : (time_t) val); }
/*! Find the target in first word of psz_args or use $@ (the current stack) if none. We also allow $@ or @ explicitly as a target name to mean the current target on the stack. NULL is returned if a lookup of the target name was not found. ppsz_target is to the name looked up. */ file_t * get_target(char **ppsz_args, /*out*/ const char **ppsz_target) { if (!*ppsz_args || !**ppsz_args) { file_t *p_target = (file_t *) get_current_target(); /* Use current target */ if (p_target && p_target->name) { *ppsz_args = (char *) p_target->name; } else { printf(_("Default target not found here. You must supply one\n")); return NULL; } } *ppsz_target = get_word(ppsz_args); /* As a special case, we'll allow $@ or @ for the current target. */ if ( 0 == strcmp("$@", *ppsz_target) || 0 == strcmp("@", *ppsz_target) ) { if (p_stack && p_stack->p_target && p_stack->p_target->name) *ppsz_target = p_stack->p_target->name; else { printf(_("No current target found for $@ - supply a target name.\n")); return NULL; } } { file_t *p_target = lookup_file (*ppsz_target); if (!p_target) printf(_("Target \"%s\" doesn't appear to be a target name.\n"), *ppsz_target); return p_target; } }
void convert_to_pattern (void) { register struct dep *d, *d2; register struct file *f; register char *rulename; register unsigned int slen, s2len; /* Compute maximum length of all the suffixes. */ maxsuffix = 0; for (d = suffix_file->deps; d != 0; d = d->next) { register unsigned int namelen = strlen (dep_name (d)); if (namelen > maxsuffix) maxsuffix = namelen; } rulename = (char *) alloca ((maxsuffix * 2) + 1); for (d = suffix_file->deps; d != 0; d = d->next) { /* Make a rule that is just the suffix, with no deps or commands. This rule exists solely to disqualify match-anything rules. */ convert_suffix_rule (dep_name (d), (char *) 0, (struct commands *) 0); f = d->file; if (f->cmds != 0) /* Record a pattern for this suffix's null-suffix rule. */ convert_suffix_rule ("", dep_name (d), f->cmds); /* Record a pattern for each of this suffix's two-suffix rules. */ slen = strlen (dep_name (d)); bcopy (dep_name (d), rulename, slen); for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next) { s2len = strlen (dep_name (d2)); if (slen == s2len && streq (dep_name (d), dep_name (d2))) continue; bcopy (dep_name (d2), rulename + slen, s2len + 1); f = lookup_file (rulename); if (f == 0 || f->cmds == 0) continue; if (s2len == 2 && rulename[slen] == '.' && rulename[slen + 1] == 'a') /* A suffix rule `.X.a:' generates the pattern rule `(%.o): %.X'. It also generates a normal `%.a: %.X' rule below. */ convert_suffix_rule ((char *) 0, /* Indicates `(%.o)'. */ dep_name (d), f->cmds); /* The suffix rule `.X.Y:' is converted to the pattern rule `%.Y: %.X'. */ convert_suffix_rule (dep_name (d2), dep_name (d), f->cmds); } } }
int file_error (int fd) { File *ptr = lookup_file (fd); if (!ptr) return -1; else return ferror(ptr->elf->fp); }
int file_eof (int fd) { File *ptr = lookup_file (fd); if (!ptr) return -1; else return epic_feof(ptr->elf); }
char *search_binary_path(char *cmd) { char *path_env_str; char *err_msg = NULL; char *searched_path; char current_search_dir[1024]; int i; char *p; /* check if it is relative path from current directory */ if (*(cmd + 0) == '.' && *(cmd + 1) == '/') { searched_path = calloc(sizeof(char), strlen(cmd) + 1); strcpy(searched_path, cmd); err_msg = "relative pat"; goto found; } if (strchr(cmd, '/') != NULL) { /* slash containing => denote relative path */ searched_path = calloc(sizeof(char), strlen(cmd) + 1); strcpy(searched_path, cmd); err_msg = "containing /"; goto found; } /* search by environt variable PATH */ path_env_str = getenv("PATH"); if (path_env_str == NULL) err_msg = "getenv() returned NULL to get PATH"; i = 0; p = path_env_str; memset(current_search_dir, 0x00, sizeof(current_search_dir)); do { if ( *p == ':' || *p == '\0' ) { current_search_dir[i] = '\0'; searched_path = lookup_file(current_search_dir, cmd); if (searched_path != NULL) { err_msg = "Found"; goto found; } else { i = 0; } } else { current_search_dir[i] = *p; i++; } p++; } while( *p != '\0' ); if (searched_path == NULL) { err_msg = "not found in environment path"; } found: printf("%s\n", searched_path); return searched_path; error: return NULL; }
int file_close (int fd) { File *ptr = lookup_file (fd); if (!ptr) return -1; else remove_file (ptr); return 0; }
intmax_t file_tell (int fd) { File *ptr = lookup_file (fd); if (!ptr) return -1; else /* XXX Should call ftello(). */ return (intmax_t)ftell(ptr->elf->fp); }
int file_rewind (int fd) { File *ptr = lookup_file (fd); if (!ptr) return -1; else { rewind(ptr->elf->fp); return ferror(ptr->elf->fp); } }
/* LONG should support 64 bit */ int file_seek (int fd, off_t offset, const char *whence) { File *ptr = lookup_file (fd); if (!ptr) return -1; if (!my_stricmp(whence, "SET")) return fseek(ptr->elf->fp, offset, SEEK_SET); else if (!my_stricmp(whence, "CUR")) return fseek(ptr->elf->fp, offset, SEEK_CUR); else if (!my_stricmp(whence, "END")) return fseek(ptr->elf->fp, offset, SEEK_END); else return -1; }
gboolean nemo_list_model_get_tree_iter_from_file (NemoListModel *model, NemoFile *file, NemoDirectory *directory, GtkTreeIter *iter) { GSequenceIter *ptr; ptr = lookup_file (model, file, directory); if (!ptr) { return FALSE; } nemo_list_model_ptr_to_iter (model, ptr, iter); return TRUE; }
gboolean athena_list_model_get_tree_iter_from_file (AthenaListModel *model, AthenaFile *file, AthenaDirectory *directory, GtkTreeIter *iter) { GSequenceIter *ptr; ptr = lookup_file (model, file, directory); if (!ptr) { return FALSE; } athena_list_model_ptr_to_iter (model, ptr, iter); return TRUE; }
char * file_read (int fd) { File *ptr = lookup_file(fd); if (!ptr) return malloc_strdup(empty_string); else { char *ret = NULL; size_t retlen = 0; size_t retbufsiz = 0; char *end = NULL; if (ptr->elf->fp) clearerr(ptr->elf->fp); for (;;) { retbufsiz += 4096; RESIZE(ret, char, retbufsiz); ret[retlen] = 0; /* Keep this -- C requires it! */ if (!epic_fgets(ret + retlen, retbufsiz - retlen, ptr->elf)) break; if ((end = strchr(ret + retlen, '\n'))) break; retlen = retbufsiz - 1; } /* Do we need to truncate the result? */ if (end) *end = 0; /* Either the newline */ else if ( (ptr->elf->fp) && (ferror(ptr->elf->fp)) ) *ret = 0; /* Or the whole thing on error */ /* XXX TODO -- this is just temporary */ if (invalid_utf8str(ret)) { const char *encodingx; encodingx = find_recoding("scripts", NULL, NULL); recode_with_iconv(encodingx, NULL, &ret, &retlen); } return ret; } }
/*! Show a expression. Set "expand" to 1 if you want variable definitions inside the displayed value expanded. */ bool dbg_cmd_show_exp (char *psz_varname, bool expand) { if (!psz_varname || 0==strlen(psz_varname)) { printf(_("You need to supply a variable name.\n")); return false; } else { variable_t *p_v; variable_set_t *p_set = NULL; variable_set_list_t *p_file_vars = NULL; if (p_stack && p_stack->p_target && p_stack->p_target->name) { const char *psz_target = p_stack->p_target->name; file_t *p_target = lookup_file (psz_target); if (p_target) { initialize_file_variables (p_target, 0); set_file_variables (p_target); p_file_vars = p_target->variables; p_set = p_file_vars->set; } } if (p_set) { p_v = lookup_variable_in_set(psz_varname, strlen(psz_varname), p_set); if (!p_v) /* May be a global variable. */ p_v = lookup_variable (psz_varname, strlen (psz_varname)); } else { p_v = lookup_variable (psz_varname, strlen (psz_varname)); } if (p_v) { if (expand) { print_variable_expand(p_v); } else print_variable(p_v); } else { if (expand) printf("%s\n", variable_expand_set(psz_varname, p_file_vars)); else { try_without_dollar(psz_varname); return false; } } } return true; }
static void do_handleinfo (void) { const char *handlename = get_handle (); MateVFSResult result; MateVFSHandle *handle = lookup_file (handlename); MateVFSFileInfo *info; if (!handle) return; info = mate_vfs_file_info_new (); result = mate_vfs_get_file_info_from_handle (handle, info, MATE_VFS_FILE_INFO_GET_MIME_TYPE); if (show_if_error (result, "getting info from handle: ", handlename)) return; print_info (info); mate_vfs_file_info_unref (info); }
/* * file_write: Write something to a file or logfile * * logtype: 0 if 'fd' is an $open() refnum. * 1 if 'fd' is a /window refnum. * 2 if 'fd' is a /log refnum. * fd: A reference number, depending on the type of 'logtype' * stuff: what should be written to the file. * * XXX - I think writes to logfiles should be sent back to the logging funcs */ static int file_write (int logtype, int fd, const char *stuff) { File *ptr; int retval; if (logtype == 2) /* General logfile */ ptr = NULL /* */; else if (logtype == 1) /* Window logfile */ ptr = lookup_window_logfile(fd); else ptr = lookup_file(fd); if (!ptr || !ptr->elf->fp) return -1; /* XXX This should call add_to_log if it's a logfile */ retval = fprintf(ptr->elf->fp, "%s\n", stuff); /* XXX utf8 XXX */ if ((fflush(ptr->elf->fp)) == EOF) return -1; return retval; }
static void do_seek (void) { char *handle; int offset; MateVFSHandle *from_handle; MateVFSResult result; handle = get_handle (); offset = get_int (); if (offset < 0) { fprintf (vfserr, "Can't seek to %d bytes offset\n", offset); return; } from_handle = lookup_file (handle); if (!from_handle) return; result = mate_vfs_seek (from_handle, MATE_VFS_SEEK_START, offset); if (show_if_error (result, "seek ", handle)) return; }
char * file_read (int fd) { File *ptr = lookup_file(fd); if (!ptr) return malloc_strdup(empty_string); else { char *ret = NULL; char *end = NULL; size_t len = 0; size_t newlen = 0; if (ptr->elf->fp) clearerr(ptr->elf->fp); for (;;) { newlen += 4096; RESIZE(ret, char, newlen); ret[len] = 0; /* Keep this -- C requires it! */ if (!epic_fgets(ret + len, newlen - len, ptr->elf)) break; if ((end = strchr(ret + len, '\n'))) break; len = newlen - 1; } /* Do we need to truncate the result? */ if (end) *end = 0; /* Either the newline */ else if ( (ptr->elf->fp) && (ferror(ptr->elf->fp)) ) *ret = 0; /* Or the whole thing on error */ return ret; } }
char * file_readb (int fd, int numb) { File *ptr = lookup_file(fd); if (!ptr) return malloc_strdup(empty_string); else { char *blah = (char *)new_malloc(numb+1); char *bleh = NULL; if (ptr->elf->fp) { clearerr(ptr->elf->fp); numb = fread(blah, 1, numb, ptr->elf->fp); #ifdef HAVE_LIBARCHIVE } else if (ptr->elf->a) { numb = archive_read_data(ptr->elf->a, blah, numb); #endif } else { /* others */ } bleh = enquote_it(blah, numb); new_free(&blah); return bleh; } }
FILE_TIMESTAMP f_mtime (struct file *file, int search) { FILE_TIMESTAMP mtime; /* File's mtime is not known; must get it from the system. */ #ifndef NO_ARCHIVES if (ar_name (file->name)) { /* This file is an archive-member reference. */ char *arname, *memname; struct file *arfile; time_t member_date; /* Find the archive's name. */ ar_parse_name (file->name, &arname, &memname); /* Find the modification time of the archive itself. Also allow for its name to be changed via VPATH search. */ arfile = lookup_file (arname); if (arfile == 0) arfile = enter_file (strcache_add (arname)); mtime = f_mtime (arfile, search); check_renamed (arfile); if (search && strcmp (arfile->hname, arname)) { /* The archive's name has changed. Change the archive-member reference accordingly. */ char *name; unsigned int arlen, memlen; arlen = strlen (arfile->hname); memlen = strlen (memname); name = xmalloc (arlen + 1 + memlen + 2); memcpy (name, arfile->hname, arlen); name[arlen] = '('; memcpy (name + arlen + 1, memname, memlen); name[arlen + 1 + memlen] = ')'; name[arlen + 1 + memlen + 1] = '\0'; /* If the archive was found with GPATH, make the change permanent; otherwise defer it until later. */ if (arfile->name == arfile->hname) rename_file (file, name); else rehash_file (file, name); check_renamed (file); } free (arname); file->low_resolution_time = 1; if (mtime == NONEXISTENT_MTIME) /* The archive doesn't exist, so its members don't exist either. */ return NONEXISTENT_MTIME; member_date = ar_member_date (file->hname); mtime = (member_date == (time_t) -1 ? NONEXISTENT_MTIME : file_timestamp_cons (file->hname, member_date, 0)); } else #endif { mtime = name_mtime (file->name); if (mtime == NONEXISTENT_MTIME && search && !file->ignore_vpath) { /* If name_mtime failed, search VPATH. */ const char *name = vpath_search (file->name, &mtime, NULL, NULL); if (name /* Last resort, is it a library (-lxxx)? */ || (file->name[0] == '-' && file->name[1] == 'l' && (name = library_search (file->name, &mtime)) != 0)) { if (mtime != UNKNOWN_MTIME) /* vpath_search and library_search store UNKNOWN_MTIME if they didn't need to do a stat call for their work. */ file->last_mtime = mtime; /* If we found it in VPATH, see if it's in GPATH too; if so, change the name right now; if not, defer until after the dependencies are updated. */ if (gpath_search (name, strlen(name) - strlen(file->name) - 1)) { rename_file (file, name); check_renamed (file); return file_mtime (file); } rehash_file (file, name); check_renamed (file); /* If the result of a vpath search is -o or -W, preserve it. Otherwise, find the mtime of the resulting file. */ if (mtime != OLD_MTIME && mtime != NEW_MTIME) mtime = name_mtime (name); } } } /* Files can have bogus timestamps that nothing newly made will be "newer" than. Updating their dependents could just result in loops. So notify the user of the anomaly with a warning. We only need to do this once, for now. */ if (!clock_skew_detected && mtime != NONEXISTENT_MTIME && mtime != NEW_MTIME && !file->updated) { static FILE_TIMESTAMP adjusted_now; FILE_TIMESTAMP adjusted_mtime = mtime; #if defined(WINDOWS32) || defined(__MSDOS__) /* Experimentation has shown that FAT filesystems can set file times up to 3 seconds into the future! Play it safe. */ #define FAT_ADJ_OFFSET (FILE_TIMESTAMP) 3 FILE_TIMESTAMP adjustment = FAT_ADJ_OFFSET << FILE_TIMESTAMP_LO_BITS; if (ORDINARY_MTIME_MIN + adjustment <= adjusted_mtime) adjusted_mtime -= adjustment; #elif defined(__EMX__) /* FAT filesystems round time to the nearest even second! Allow for any file (NTFS or FAT) to perhaps suffer from this brain damage. */ FILE_TIMESTAMP adjustment = (((FILE_TIMESTAMP_S (adjusted_mtime) & 1) == 0 && FILE_TIMESTAMP_NS (adjusted_mtime) == 0) ? (FILE_TIMESTAMP) 1 << FILE_TIMESTAMP_LO_BITS : 0); #endif /* If the file's time appears to be in the future, update our concept of the present and try once more. */ if (adjusted_now < adjusted_mtime) { int resolution; FILE_TIMESTAMP now = file_timestamp_now (&resolution); adjusted_now = now + (resolution - 1); if (adjusted_now < adjusted_mtime) { #ifdef NO_FLOAT error (NILF, _("Warning: File '%s' has modification time in the future"), file->name); #else double from_now = (FILE_TIMESTAMP_S (mtime) - FILE_TIMESTAMP_S (now) + ((FILE_TIMESTAMP_NS (mtime) - FILE_TIMESTAMP_NS (now)) / 1e9)); char from_now_string[100]; if (from_now >= 99 && from_now <= ULONG_MAX) sprintf (from_now_string, "%lu", (unsigned long) from_now); else sprintf (from_now_string, "%.2g", from_now); error (NILF, _("Warning: File '%s' has modification time %s s in the future"), file->name, from_now_string); #endif clock_skew_detected = 1; } } } /* Store the mtime into all the entries for this file. */ if (file->double_colon) file = file->double_colon; do { /* If this file is not implicit but it is intermediate then it was made so by the .INTERMEDIATE target. If this file has never been built by us but was found now, it existed before make started. So, turn off the intermediate bit so make doesn't delete it, since it didn't create it. */ if (mtime != NONEXISTENT_MTIME && file->command_state == cs_not_started && file->command_state == cs_not_started && !file->tried_implicit && file->intermediate) file->intermediate = 0; file->last_mtime = mtime; file = file->prev; } while (file != 0); return mtime; }
void convert_to_pattern (void) { struct dep *d, *d2; char *rulename; /* We will compute every potential suffix rule (.x.y) from the list of suffixes in the .SUFFIXES target's dependencies and see if it exists. First find the longest of the suffixes. */ maxsuffix = 0; for (d = suffix_file->deps; d != 0; d = d->next) { unsigned int l = strlen (dep_name (d)); if (l > maxsuffix) maxsuffix = l; } /* Space to construct the suffix rule target name. */ rulename = alloca ((maxsuffix * 2) + 1); for (d = suffix_file->deps; d != 0; d = d->next) { unsigned int slen; /* Make a rule that is just the suffix, with no deps or commands. This rule exists solely to disqualify match-anything rules. */ convert_suffix_rule (dep_name (d), 0, 0); if (d->file->cmds != 0) /* Record a pattern for this suffix's null-suffix rule. */ convert_suffix_rule ("", dep_name (d), d->file->cmds); /* Add every other suffix to this one and see if it exists as a two-suffix rule. */ slen = strlen (dep_name (d)); memcpy (rulename, dep_name (d), slen); for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next) { struct file *f; unsigned int s2len; s2len = strlen (dep_name (d2)); /* Can't build something from itself. */ if (slen == s2len && streq (dep_name (d), dep_name (d2))) continue; memcpy (rulename + slen, dep_name (d2), s2len + 1); f = lookup_file (rulename); if (f == 0 || f->cmds == 0) continue; if (s2len == 2 && rulename[slen] == '.' && rulename[slen + 1] == 'a') /* A suffix rule '.X.a:' generates the pattern rule '(%.o): %.X'. It also generates a normal '%.a: %.X' rule below. */ convert_suffix_rule (NULL, /* Indicates '(%.o)'. */ dep_name (d), f->cmds); /* The suffix rule '.X.Y:' is converted to the pattern rule '%.Y: %.X'. */ convert_suffix_rule (dep_name (d2), dep_name (d), f->cmds); } } }