tell init to go to single user mode 什么意思

本文介绍了一种在遇到tellinittogotosingleusermode命令不理解的情况下的解决方案:通过输入init0来进入单用户模式。
tell init to go to single user mode 什么意思

不懂,不过有解决办法就是:输入init 0
这是user_setup.h里的文件,你帮我修改,把完整代码发我// USER DEFINED SETTINGS // Set driver type, fonts to be loaded, pins used and SPI control method etc. // // See the User_Setup_Select.h file if you wish to be able to define multiple // setups and then easily select which setup file is used by the compiler. // // If this file is edited correctly then all the library example sketches should // run without the need to make any more changes for a particular hardware setup! // Note that some sketches are designed for a particular TFT pixel width/height // User defined information reported by "Read_User_Setup" test & diagnostics example #define USER_SETUP_INFO "User_Setup" // Define to disable all #warnings in library (can be put in User_Setup_Select.h) //#define DISABLE_ALL_LIBRARY_WARNINGS // ################################################################################## // // Section 1. Call up the right driver file and any options for it // // ################################################################################## // Define STM32 to invoke optimised processor support (only for STM32) //#define STM32 // Defining the STM32 board allows the library to optimise the performance // for UNO compatible "MCUfriend" style shields //#define NUCLEO_64_TFT //#define NUCLEO_144_TFT // STM32 8-bit parallel only: // If STN32 Port A or B pins 0-7 are used for 8-bit parallel data bus bits 0-7 // then this will improve rendering performance by a factor of ~8x //#define STM_PORTA_DATA_BUS //#define STM_PORTB_DATA_BUS // Tell the library to use parallel mode (otherwise SPI is assumed) //#define TFT_PARALLEL_8_BIT //#defined TFT_PARALLEL_16_BIT // **** 16-bit parallel ONLY for RP2040 processor **** // Display type - only define if RPi display //#define RPI_DISPLAY_TYPE // 20MHz maximum SPI // Only define one driver, the other ones must be commented out #define ILI9341_DRIVER // Generic driver for common displays //#define ILI9341_2_DRIVER // Alternative ILI9341 driver, see https://github.com/Bodmer/TFT_eSPI/issues/1172 //#define ST7735_DRIVER // Define additional parameters below for this display //#define ILI9163_DRIVER // Define additional parameters below for this display //#define S6D02A1_DRIVER //#define RPI_ILI9486_DRIVER // 20MHz maximum SPI //#define HX8357D_DRIVER //#define ILI9481_DRIVER //#define ILI9486_DRIVER //#define ILI9488_DRIVER // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high) //#define ST7789_DRIVER // Full configuration option, define additional parameters below for this display //#define ST7789_2_DRIVER // Minimal configuration option, define additional parameters below for this display //#define R61581_DRIVER //#define RM68140_DRIVER //#define ST7796_DRIVER //#define SSD1351_DRIVER //#define SSD1963_480_DRIVER //#define SSD1963_800_DRIVER //#define SSD1963_800ALT_DRIVER //#define ILI9225_DRIVER #define GC9A01_DRIVER // Some displays support SPI reads via the MISO pin, other displays have a single // bi-directional SDA pin and the library will try to read this via the MOSI line. // To use the SDA line for reading data from the TFT uncomment the following line: // #define TFT_SDA_READ // This option is for ESP32 ONLY, tested with ST7789 and GC9A01 display only // For ST7735, ST7789 and ILI9341 ONLY, define the colour order IF the blue and red are swapped on your display // Try ONE option at a time to find the correct colour order for your display // #define TFT_RGB_ORDER TFT_RGB // Colour order Red-Green-Blue // #define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red // For M5Stack ESP32 module with integrated ILI9341 display ONLY, remove // in line below // #define M5STACK // For ST7789, ST7735, ILI9163 and GC9A01 ONLY, define the pixel width and height in portrait orientation // #define TFT_WIDTH 80 // #define TFT_WIDTH 128 // #define TFT_WIDTH 172 // ST7789 172 x 320 // #define TFT_WIDTH 170 // ST7789 170 x 320 // #define TFT_WIDTH 240 // ST7789 240 x 240 and 240 x 320 // #define TFT_HEIGHT 160 // #define TFT_HEIGHT 128 // #define TFT_HEIGHT 240 // ST7789 240 x 240 // #define TFT_HEIGHT 320 // ST7789 240 x 320 // #define TFT_HEIGHT 240 // GC9A01 240 x 240 // For ST7735 ONLY, define the type of display, originally this was based on the // colour of the tab on the screen protector film but this is not always true, so try // out the different options below if the screen does not display graphics correctly, // e.g. colours wrong, mirror images, or stray pixels at the edges. // Comment out ALL BUT ONE of these options for a ST7735 display driver, save this // this User_Setup file, then rebuild and upload the sketch to the board again: // #define ST7735_INITB // #define ST7735_GREENTAB // #define ST7735_GREENTAB2 // #define ST7735_GREENTAB3 // #define ST7735_GREENTAB128 // For 128 x 128 display // #define ST7735_GREENTAB160x80 // For 160 x 80 display (BGR, inverted, 26 offset) // #define ST7735_ROBOTLCD // For some RobotLCD Arduino shields (128x160, BGR, https://docs.arduino.cc/retired/getting-started-guides/TFT) // #define ST7735_REDTAB // #define ST7735_BLACKTAB // #define ST7735_REDTAB160x80 // For 160 x 80 display with 24 pixel offset // If colours are inverted (white shows as black) then uncomment one of the next // 2 lines try both options, one of the options should correct the inversion. // #define TFT_INVERSION_ON // #define TFT_INVERSION_OFF // ################################################################################## // // Section 2. Define the pins that are used to interface with the display here // // ################################################################################## // If a backlight control signal is available then define the TFT_BL pin in Section 2 // below. The backlight will be turned ON when tft.begin() is called, but the library // needs to know if the LEDs are ON with the pin HIGH or LOW. If the LEDs are to be // driven with a PWM signal or turned OFF/ON then this must be handled by the user // sketch. e.g. with digitalWrite(TFT_BL, LOW); // #define TFT_BL 32 // LED back-light control pin // #define TFT_BACKLIGHT_ON HIGH // Level to turn ON back-light (HIGH or LOW) // We must use hardware SPI, a minimum of 3 GPIO pins is needed. // Typical setup for ESP8266 NodeMCU ESP-12 is : // // Display SDO/MISO to NodeMCU pin D6 (or leave disconnected if not reading TFT) // Display LED to NodeMCU pin VIN (or 5V, see below) // Display SCK to NodeMCU pin D5 // Display SDI/MOSI to NodeMCU pin D7 // Display DC (RS/AO)to NodeMCU pin D3 // Display RESET to NodeMCU pin D4 (or RST, see below) // Display CS to NodeMCU pin D8 (or GND, see below) // Display GND to NodeMCU pin GND (0V) // Display VCC to NodeMCU 5V or 3.3V // // The TFT RESET pin can be connected to the NodeMCU RST pin or 3.3V to free up a control pin // // The DC (Data Command) pin may be labelled AO or RS (Register Select) // // With some displays such as the ILI9341 the TFT CS pin can be connected to GND if no more // SPI devices (e.g. an SD Card) are connected, in this case comment out the #define TFT_CS // line below so it is NOT defined. Other displays such at the ST7735 require the TFT CS pin // to be toggled during setup, so in these cases the TFT_CS line must be defined and connected. // // The NodeMCU D0 pin can be used for RST // // // Note: only some versions of the NodeMCU provide the USB 5V on the VIN pin // If 5V is not available at a pin you can use 3.3V but backlight brightness // will be lower. // ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP8266 SETUP ###### // For NodeMCU - use pin numbers in the form PIN_Dx where Dx is the NodeMCU pin designation /*#define TFT_MISO PIN_D6 // Automatically assigned with ESP8266 if not defined #define TFT_MOSI PIN_D7 // Automatically assigned with ESP8266 if not defined #define TFT_SCLK PIN_D5 // Automatically assigned with ESP8266 if not defined #define TFT_CS PIN_D8 // Chip select control pin D8 #define TFT_DC PIN_D3 // Data Command control pin #define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)*/ //#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V //#define TFT_BL PIN_D1 // LED back-light (only for ST7789 with backlight control pin) //#define TOUCH_CS PIN_D2 // Chip select pin (T_CS) of touch screen //#define TFT_WR PIN_D2 // Write strobe for modified Raspberry Pi TFT only // ###### FOR ESP8266 OVERLAP MODE EDIT THE PIN NUMBERS IN THE FOLLOWING LINES ###### // Overlap mode shares the ESP8266 FLASH SPI bus with the TFT so has a performance impact // but saves pins for other functions. It is best not to connect MISO as some displays // do not tristate that line when chip select is high! // Note: Only one SPI device can share the FLASH SPI lines, so a SPI touch controller // cannot be connected as well to the same SPI signals. // On NodeMCU 1.0 SD0=MISO, SD1=MOSI, CLK=SCLK to connect to TFT in overlap mode // On NodeMCU V3 S0 =MISO, S1 =MOSI, S2 =SCLK // In ESP8266 overlap mode the following must be defined //#define TFT_SPI_OVERLAP // In ESP8266 overlap mode the TFT chip select MUST connect to pin D3 //#define TFT_CS PIN_D3 //#define TFT_DC PIN_D5 // Data Command control pin //#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line) //#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V // ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP32 SETUP ###### // For ESP32 Dev board (only tested with ILI9341 display) // The hardware SPI can be mapped to any pins //#define TFT_MISO 19 //#define TFT_MOSI 23 //#define TFT_SCLK 18 //#define TFT_CS 15 // Chip select control pin //#define TFT_DC 2 // Data Command control pin //#define TFT_RST 4 // Reset pin (could connect to RST pin) //#define TFT_RST -1 // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST // For ESP32 Dev board (only tested with GC9A01 display) // The hardware SPI can be mapped to any pins #define TFT_MOSI 3 // In some display driver board, it might be written as "SDA" and so on. #define TFT_SCLK 2 #define TFT_CS 6 // Chip select control pin #define TFT_DC 10 // Data Command control pin #define TFT_RST 7 // Reset pin (could connect to Arduino RESET pin) //#define TFT_BL 22 // LED back-light //#define TOUCH_CS 21 // Chip select pin (T_CS) of touch screen //#define TFT_WR 22 // Write strobe for modified Raspberry Pi TFT only // For the M5Stack module use these #define lines //#define TFT_MISO 19 //#define TFT_MOSI 23 //#define TFT_SCLK 18 //#define TFT_CS 14 // Chip select control pin //#define TFT_DC 27 // Data Command control pin //#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin) //#define TFT_BL 32 // LED back-light (required for M5Stack) // ###### EDIT THE PINs BELOW TO SUIT YOUR ESP32 PARALLEL TFT SETUP ###### // The library supports 8-bit parallel TFTs with the ESP32, the pin // selection below is compatible with ESP32 boards in UNO format. // Wemos D32 boards need to be modified, see diagram in Tools folder. // Only ILI9481 and ILI9341 based displays have been tested! // Parallel bus is only supported for the STM32 and ESP32 // Example below is for ESP32 Parallel interface with UNO displays // Tell the library to use 8-bit parallel mode (otherwise SPI is assumed) //#define TFT_PARALLEL_8_BIT // The ESP32 and TFT the pins used for testing are: //#define TFT_CS 33 // Chip select control pin (library pulls permanently low //#define TFT_DC 15 // Data Command control pin - must use a pin in the range 0-31 //#define TFT_RST 32 // Reset pin, toggles on startup //#define TFT_WR 4 // Write strobe control pin - must use a pin in the range 0-31 //#define TFT_RD 2 // Read strobe control pin //#define TFT_D0 12 // Must use pins in the range 0-31 for the data bus //#define TFT_D1 13 // so a single register write sets/clears all bits. //#define TFT_D2 26 // Pins can be randomly assigned, this does not affect //#define TFT_D3 25 // TFT screen update performance. //#define TFT_D4 17 //#define TFT_D5 16 //#define TFT_D6 27 //#define TFT_D7 14 // ###### EDIT THE PINs BELOW TO SUIT YOUR STM32 SPI TFT SETUP ###### // The TFT can be connected to SPI port 1 or 2 //#define TFT_SPI_PORT 1 // SPI port 1 maximum clock rate is 55MHz //#define TFT_MOSI PA7 //#define TFT_MISO PA6 //#define TFT_SCLK PA5 //#define TFT_SPI_PORT 2 // SPI port 2 maximum clock rate is 27MHz //#define TFT_MOSI PB15 //#define TFT_MISO PB14 //#define TFT_SCLK PB13 // Can use Ardiuno pin references, arbitrary allocation, TFT_eSPI controls chip select //#define TFT_CS D5 // Chip select control pin to TFT CS //#define TFT_DC D6 // Data Command control pin to TFT DC (may be labelled RS = Register Select) //#define TFT_RST D7 // Reset pin to TFT RST (or RESET) // OR alternatively, we can use STM32 port reference names PXnn //#define TFT_CS PE11 // Nucleo-F767ZI equivalent of D5 //#define TFT_DC PE9 // Nucleo-F767ZI equivalent of D6 //#define TFT_RST PF13 // Nucleo-F767ZI equivalent of D7 //#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to processor reset // Use an Arduino pin for initial testing as connecting to processor reset // may not work (pulse too short at power up?) // ################################################################################## // // Section 3. Define the fonts that are to be used here // // ################################################################################## // Comment out the #defines below with // to stop that font being loaded // The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not // normally necessary. If all fonts are loaded the extra FLASH space required is // about 17Kbytes. To save FLASH space only enable the fonts you need! #define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH #define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters #define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters #define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm #define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-. #define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-. //#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT #define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts // Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded // this will save ~20kbytes of FLASH #define SMOOTH_FONT // ################################################################################## // // Section 4. Other options // // ################################################################################## // For RP2040 processor and SPI displays, uncomment the following line to use the PIO interface. //#define RP2040_PIO_SPI // Leave commented out to use standard RP2040 SPI port interface // For RP2040 processor and 8 or 16-bit parallel displays: // The parallel interface write cycle period is derived from a division of the CPU clock // speed so scales with the processor clock. This means that the divider ratio may need // to be increased when overclocking. It may also need to be adjusted dependant on the // display controller type (ILI94341, HX8357C etc.). If RP2040_PIO_CLK_DIV is not defined // the library will set default values which may not suit your display. // The display controller data sheet will specify the minimum write cycle period. The // controllers often work reliably for shorter periods, however if the period is too short // the display may not initialise or graphics will become corrupted. // PIO write cycle frequency = (CPU clock/(4 * RP2040_PIO_CLK_DIV)) //#define RP2040_PIO_CLK_DIV 1 // 32ns write cycle at 125MHz CPU clock //#define RP2040_PIO_CLK_DIV 2 // 64ns write cycle at 125MHz CPU clock //#define RP2040_PIO_CLK_DIV 3 // 96ns write cycle at 125MHz CPU clock // For the RP2040 processor define the SPI port channel used (default 0 if undefined) //#define TFT_SPI_PORT 1 // Set to 0 if SPI0 pins are used, or 1 if spi1 pins used // For the STM32 processor define the SPI port channel used (default 1 if undefined) //#define TFT_SPI_PORT 2 // Set to 1 for SPI port 1, or 2 for SPI port 2 // Define the SPI clock frequency, this affects the graphics rendering speed. Too // fast and the TFT driver will not keep up and display corruption appears. // With an ILI9341 display 40MHz works OK, 80MHz sometimes fails // With a ST7735 display more than 27MHz may not work (spurious pixels and lines) // With an ILI9163 display 27 MHz works OK. // #define SPI_FREQUENCY 1000000 // #define SPI_FREQUENCY 5000000 // #define SPI_FREQUENCY 10000000 // #define SPI_FREQUENCY 20000000 #define SPI_FREQUENCY 27000000 // #define SPI_FREQUENCY 40000000 // #define SPI_FREQUENCY 55000000 // STM32 SPI1 only (SPI2 maximum is 27MHz) // #define SPI_FREQUENCY 80000000 // Optional reduced SPI frequency for reading TFT #define SPI_READ_FREQUENCY 20000000 // The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here: #define SPI_TOUCH_FREQUENCY 2500000 // The ESP32 has 2 free SPI ports i.e. VSPI and HSPI, the VSPI is the default. // If the VSPI port is in use and pins are not accessible (e.g. TTGO T-Beam) // then uncomment the following line: //#define USE_HSPI_PORT // Comment out the following #define if "SPI Transactions" do not need to be // supported. When commented out the code size will be smaller and sketches will // run slightly faster, so leave it commented out unless you need it! // Transaction support is needed to work with SD library but not needed with TFT_SdFat // Transaction support is required if other SPI devices are connected. // Transactions are automatically enabled by the library for an ESP32 (to use HAL mutex) // so changing it here has no effect // #define SUPPORT_TRANSACTIONS
最新发布
09-26
/* -*- C -*- * main.c -- the bare scullp char module * * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet * Copyright (C) 2001 O'Reilly & Associates * * The source code in this file can be freely used, adapted, * and redistributed in source or binary form, so long as an * acknowledgment appears in derived source files. The citation * should list that the code comes from the book "Linux Device * Drivers" by Alessandro Rubini and Jonathan Corbet, published * by O'Reilly & Associates. No warranty is attached; * we cannot take responsibility for errors or fitness for use. * * $Id: _main.c.in,v 1.21 2004/10/14 20:11:39 corbet Exp $ */ #include <linux/config.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/kernel.h> /* printk() */ #include <linux/slab.h> /* kmalloc() */ #include <linux/fs.h> /* everything... */ #include <linux/errno.h> /* error codes */ #include <linux/types.h> /* size_t */ #include <linux/proc_fs.h> #include <linux/fcntl.h> /* O_ACCMODE */ #include <linux/aio.h> #include <asm/uaccess.h> #include "scullp.h" /* local definitions */ int scullp_major = SCULLP_MAJOR; int scullp_devs = SCULLP_DEVS; /* number of bare scullp devices */ int scullp_qset = SCULLP_QSET; int scullp_order = SCULLP_ORDER; module_param(scullp_major, int, 0); module_param(scullp_devs, int, 0); module_param(scullp_qset, int, 0); module_param(scullp_order, int, 0); MODULE_AUTHOR("Alessandro Rubini"); MODULE_LICENSE("Dual BSD/GPL"); struct scullp_dev *scullp_devices; /* allocated in scullp_init */ int scullp_trim(struct scullp_dev *dev); void scullp_cleanup(void); #ifdef SCULLP_USE_PROC /* don't waste space if unused */ /* * The proc filesystem: function to read and entry */ void scullp_proc_offset(char *buf, char **start, off_t *offset, int *len) { if (*offset == 0) return; if (*offset >= *len) { /* Not there yet */ *offset -= *len; *len = 0; } else { /* We're into the interesting stuff now */ *start = buf + *offset; *offset = 0; } } /* FIXME: Do we need this here?? It be ugly */ int scullp_read_procmem(char *buf, char **start, off_t offset, int count, int *eof, void *data) { int i, j, order, qset, len = 0; int limit = count - 80; /* Don't print more than this */ struct scullp_dev *d; *start = buf; for(i = 0; i < scullp_devs; i++) { d = &scullp_devices[i]; if (down_interruptible (&d->sem)) return -ERESTARTSYS; qset = d->qset; /* retrieve the features of each device */ order = d->order; len += sprintf(buf+len,"\nDevice %i: qset %i, order %i, sz %li\n", i, qset, order, (long)(d->size)); for (; d; d = d->next) { /* scan the list */ len += sprintf(buf+len," item at %p, qset at %p\n",d,d->data); scullp_proc_offset (buf, start, &offset, &len); if (len > limit) goto out; if (d->data && !d->next) /* dump only the last item - save space */ for (j = 0; j < qset; j++) { if (d->data[j]) len += sprintf(buf+len," % 4i:%8p\n",j,d->data[j]); scullp_proc_offset (buf, start, &offset, &len); if (len > limit) goto out; } } out: up (&scullp_devices[i].sem); if (len > limit) break; } *eof = 1; return len; } #endif /* SCULLP_USE_PROC */ /* * Open and close */ int scullp_open (struct inode *inode, struct file *filp) { struct scullp_dev *dev; /* device information */ /* Find the device */ dev = container_of(inode->i_cdev, struct scullp_dev, cdev); /* now trim to 0 the length of the device if open was write-only */ if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) { if (down_interruptible (&dev->sem)) return -ERESTARTSYS; scullp_trim(dev); /* ignore errors */ up (&dev->sem); } /* and use filp->private_data to point to the device data */ filp->private_data = dev; return 0; /* success */ } int scullp_release (struct inode *inode, struct file *filp) { return 0; } /* * Follow the list */ struct scullp_dev *scullp_follow(struct scullp_dev *dev, int n) { while (n--) { if (!dev->next) { dev->next = kmalloc(sizeof(struct scullp_dev), GFP_KERNEL); memset(dev->next, 0, sizeof(struct scullp_dev)); } dev = dev->next; continue; } return dev; } /* * Data management: read and write */ ssize_t scullp_read (struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { struct scullp_dev *dev = filp->private_data; /* the first listitem */ struct scullp_dev *dptr; int quantum = PAGE_SIZE << dev->order; int qset = dev->qset; int itemsize = quantum * qset; /* how many bytes in the listitem */ int item, s_pos, q_pos, rest; ssize_t retval = 0; if (down_interruptible (&dev->sem)) return -ERESTARTSYS; if (*f_pos > dev->size) goto nothing; if (*f_pos + count > dev->size) count = dev->size - *f_pos; /* find listitem, qset index, and offset in the quantum */ item = ((long) *f_pos) / itemsize; rest = ((long) *f_pos) % itemsize; s_pos = rest / quantum; q_pos = rest % quantum; /* follow the list up to the right position (defined elsewhere) */ dptr = scullp_follow(dev, item); if (!dptr->data) goto nothing; /* don't fill holes */ if (!dptr->data[s_pos]) goto nothing; if (count > quantum - q_pos) count = quantum - q_pos; /* read only up to the end of this quantum */ if (copy_to_user (buf, dptr->data[s_pos]+q_pos, count)) { retval = -EFAULT; goto nothing; } up (&dev->sem); *f_pos += count; return count; nothing: up (&dev->sem); return retval; } ssize_t scullp_write (struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { struct scullp_dev *dev = filp->private_data; struct scullp_dev *dptr; int quantum = PAGE_SIZE << dev->order; int qset = dev->qset; int itemsize = quantum * qset; int item, s_pos, q_pos, rest; ssize_t retval = -ENOMEM; /* our most likely error */ if (down_interruptible (&dev->sem)) return -ERESTARTSYS; /* find listitem, qset index and offset in the quantum */ item = ((long) *f_pos) / itemsize; rest = ((long) *f_pos) % itemsize; s_pos = rest / quantum; q_pos = rest % quantum; /* follow the list up to the right position */ dptr = scullp_follow(dev, item); if (!dptr->data) { dptr->data = kmalloc(qset * sizeof(void *), GFP_KERNEL); if (!dptr->data) goto nomem; memset(dptr->data, 0, qset * sizeof(char *)); } /* Here's the allocation of a single quantum */ if (!dptr->data[s_pos]) { dptr->data[s_pos] = (void *)__get_free_pages(GFP_KERNEL, dptr->order); if (!dptr->data[s_pos]) goto nomem; memset(dptr->data[s_pos], 0, PAGE_SIZE << dptr->order); } if (count > quantum - q_pos) count = quantum - q_pos; /* write only up to the end of this quantum */ if (copy_from_user (dptr->data[s_pos]+q_pos, buf, count)) { retval = -EFAULT; goto nomem; } *f_pos += count; /* update the size */ if (dev->size < *f_pos) dev->size = *f_pos; up (&dev->sem); return count; nomem: up (&dev->sem); return retval; } /* * The ioctl() implementation */ int scullp_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { int err = 0, ret = 0, tmp; /* don't even decode wrong cmds: better returning ENOTTY than EFAULT */ if (_IOC_TYPE(cmd) != SCULLP_IOC_MAGIC) return -ENOTTY; if (_IOC_NR(cmd) > SCULLP_IOC_MAXNR) return -ENOTTY; /* * the type is a bitmask, and VERIFY_WRITE catches R/W * transfers. Note that the type is user-oriented, while * verify_area is kernel-oriented, so the concept of "read" and * "write" is reversed */ if (_IOC_DIR(cmd) & _IOC_READ) err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); if (err) return -EFAULT; switch(cmd) { case SCULLP_IOCRESET: scullp_qset = SCULLP_QSET; scullp_order = SCULLP_ORDER; break; case SCULLP_IOCSORDER: /* Set: arg points to the value */ ret = __get_user(scullp_order, (int __user *) arg); break; case SCULLP_IOCTORDER: /* Tell: arg is the value */ scullp_order = arg; break; case SCULLP_IOCGORDER: /* Get: arg is pointer to result */ ret = __put_user (scullp_order, (int __user *) arg); break; case SCULLP_IOCQORDER: /* Query: return it (it's positive) */ return scullp_order; case SCULLP_IOCXORDER: /* eXchange: use arg as pointer */ tmp = scullp_order; ret = __get_user(scullp_order, (int __user *) arg); if (ret == 0) ret = __put_user(tmp, (int __user *) arg); break; case SCULLP_IOCHORDER: /* sHift: like Tell + Query */ tmp = scullp_order; scullp_order = arg; return tmp; case SCULLP_IOCSQSET: ret = __get_user(scullp_qset, (int __user *) arg); break; case SCULLP_IOCTQSET: scullp_qset = arg; break; case SCULLP_IOCGQSET: ret = __put_user(scullp_qset, (int __user *)arg); break; case SCULLP_IOCQQSET: return scullp_qset; case SCULLP_IOCXQSET: tmp = scullp_qset; ret = __get_user(scullp_qset, (int __user *)arg); if (ret == 0) ret = __put_user(tmp, (int __user *)arg); break; case SCULLP_IOCHQSET: tmp = scullp_qset; scullp_qset = arg; return tmp; default: /* redundant, as cmd was checked against MAXNR */ return -ENOTTY; } return ret; } /* * The "extended" operations */ loff_t scullp_llseek (struct file *filp, loff_t off, int whence) { struct scullp_dev *dev = filp->private_data; long newpos; switch(whence) { case 0: /* SEEK_SET */ newpos = off; break; case 1: /* SEEK_CUR */ newpos = filp->f_pos + off; break; case 2: /* SEEK_END */ newpos = dev->size + off; break; default: /* can't happen */ return -EINVAL; } if (newpos<0) return -EINVAL; filp->f_pos = newpos; return newpos; } /* * A simple asynchronous I/O implementation. */ struct async_work { struct kiocb *iocb; int result; struct work_struct work; }; /* * "Complete" an asynchronous operation. */ static void scullp_do_deferred_op(void *p) { struct async_work *stuff = (struct async_work *) p; aio_complete(stuff->iocb, stuff->result, 0); kfree(stuff); } static int scullp_defer_op(int write, struct kiocb *iocb, char __user *buf, size_t count, loff_t pos) { struct async_work *stuff; int result; /* Copy now while we can access the buffer */ if (write) result = scullp_write(iocb->ki_filp, buf, count, &pos); else result = scullp_read(iocb->ki_filp, buf, count, &pos); /* If this is a synchronous IOCB, we return our status now. */ if (is_sync_kiocb(iocb)) return result; /* Otherwise defer the completion for a few milliseconds. */ stuff = kmalloc (sizeof (*stuff), GFP_KERNEL); if (stuff == NULL) return result; /* No memory, just complete now */ stuff->iocb = iocb; stuff->result = result; INIT_WORK(&stuff->work, scullp_do_deferred_op, stuff); schedule_delayed_work(&stuff->work, HZ/100); return -EIOCBQUEUED; } static ssize_t scullp_aio_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos) { return scullp_defer_op(0, iocb, buf, count, pos); } static ssize_t scullp_aio_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos) { return scullp_defer_op(1, iocb, (char __user *) buf, count, pos); } /* * Mmap *is* available, but confined in a different file */ extern int scullp_mmap(struct file *filp, struct vm_area_struct *vma); /* * The fops */ struct file_operations scullp_fops = { .owner = THIS_MODULE, .llseek = scullp_llseek, .read = scullp_read, .write = scullp_write, .ioctl = scullp_ioctl, .mmap = scullp_mmap, .open = scullp_open, .release = scullp_release, .aio_read = scullp_aio_read, .aio_write = scullp_aio_write, }; int scullp_trim(struct scullp_dev *dev) { struct scullp_dev *next, *dptr; int qset = dev->qset; /* "dev" is not-null */ int i; if (dev->vmas) /* don't trim: there are active mappings */ return -EBUSY; for (dptr = dev; dptr; dptr = next) { /* all the list items */ if (dptr->data) { /* This code frees a whole quantum-set */ for (i = 0; i < qset; i++) if (dptr->data[i]) free_pages((unsigned long)(dptr->data[i]), dptr->order); kfree(dptr->data); dptr->data=NULL; } next=dptr->next; if (dptr != dev) kfree(dptr); /* all of them but the first */ } dev->size = 0; dev->qset = scullp_qset; dev->order = scullp_order; dev->next = NULL; return 0; } static void scullp_setup_cdev(struct scullp_dev *dev, int index) { int err, devno = MKDEV(scullp_major, index); cdev_init(&dev->cdev, &scullp_fops); dev->cdev.owner = THIS_MODULE; dev->cdev.ops = &scullp_fops; err = cdev_add (&dev->cdev, devno, 1); /* Fail gracefully if need be */ if (err) printk(KERN_NOTICE "Error %d adding scull%d", err, index); } /* * Finally, the module stuff */ int scullp_init(void) { int result, i; dev_t dev = MKDEV(scullp_major, 0); /* * Register your major, and accept a dynamic number. */ if (scullp_major) result = register_chrdev_region(dev, scullp_devs, "scullp"); else { result = alloc_chrdev_region(&dev, 0, scullp_devs, "scullp"); scullp_major = MAJOR(dev); } if (result < 0) return result; /* * allocate the devices -- we can't have them static, as the number * can be specified at load time */ scullp_devices = kmalloc(scullp_devs*sizeof (struct scullp_dev), GFP_KERNEL); if (!scullp_devices) { result = -ENOMEM; goto fail_malloc; } memset(scullp_devices, 0, scullp_devs*sizeof (struct scullp_dev)); for (i = 0; i < scullp_devs; i++) { scullp_devices[i].order = scullp_order; scullp_devices[i].qset = scullp_qset; sema_init (&scullp_devices[i].sem, 1); scullp_setup_cdev(scullp_devices + i, i); } #ifdef SCULLP_USE_PROC /* only when available */ create_proc_read_entry("scullpmem", 0, NULL, scullp_read_procmem, NULL); #endif return 0; /* succeed */ fail_malloc: unregister_chrdev_region(dev, scullp_devs); return result; } void scullp_cleanup(void) { int i; #ifdef SCULLP_USE_PROC remove_proc_entry("scullpmem", NULL); #endif for (i = 0; i < scullp_devs; i++) { cdev_del(&scullp_devices[i].cdev); scullp_trim(scullp_devices + i); } kfree(scullp_devices); unregister_chrdev_region(MKDEV (scullp_major, 0), scullp_devs); } module_init(scullp_init); module_exit(scullp_cleanup);详细说一下这个文件里的异步IO机制
06-27
r"""HTTP/1.1 client library <intro stuff goes here> <other stuff, too> HTTPConnection goes through a number of "states", which define when a client may legally make another request or fetch the response for a particular request. This diagram details these state transitions: (null) | | HTTPConnection() v Idle | | putrequest() v Request-started | | ( putheader() )* endheaders() v Request-sent |\_____________________________ | | getresponse() raises | response = getresponse() | ConnectionError v v Unread-response Idle [Response-headers-read] |\____________________ | | | response.read() | putrequest() v v Idle Req-started-unread-response ______/| / | response.read() | | ( putheader() )* endheaders() v v Request-started Req-sent-unread-response | | response.read() v Request-sent This diagram presents the following rules: -- a second request may not be started until {response-headers-read} -- a response [object] cannot be retrieved until {request-sent} -- there is no differentiation between an unread response body and a partially read response body Note: this enforcement is applied by the HTTPConnection class. The HTTPResponse class does not enforce this state machine, which implies sophisticated clients may accelerate the request/response pipeline. Caution should be taken, though: accelerating the states beyond the above pattern may imply knowledge of the server's connection-close behavior for certain requests. For example, it is impossible to tell whether the server will close the connection UNTIL the response headers have been read; this means that further requests cannot be placed into the pipeline until it is known that the server will NOT be closing the connection. Logical State __state __response ------------- ------- ---------- Idle _CS_IDLE None Request-started _CS_REQ_STARTED None Request-sent _CS_REQ_SENT None Unread-response _CS_IDLE <response_class> Req-started-unread-response _CS_REQ_STARTED <response_class> Req-sent-unread-response _CS_REQ_SENT <response_class> """ import email.parser import email.message import errno import http import io import re import socket import sys import collections.abc from urllib.parse import urlsplit # HTTPMessage, parse_headers(), and the HTTP status code constants are # intentionally omitted for simplicity __all__ = ["HTTPResponse", "HTTPConnection", "HTTPException", "NotConnected", "UnknownProtocol", "UnknownTransferEncoding", "UnimplementedFileMode", "IncompleteRead", "InvalidURL", "ImproperConnectionState", "CannotSendRequest", "CannotSendHeader", "ResponseNotReady", "BadStatusLine", "LineTooLong", "RemoteDisconnected", "error", "responses"] HTTP_PORT = 80 HTTPS_PORT = 443 _UNKNOWN = 'UNKNOWN' # connection states _CS_IDLE = 'Idle' _CS_REQ_STARTED = 'Request-started' _CS_REQ_SENT = 'Request-sent' # hack to maintain backwards compatibility globals().update(http.HTTPStatus.__members__) # another hack to maintain backwards compatibility # Mapping status codes to official W3C names responses = {v: v.phrase for v in http.HTTPStatus.__members__.values()} # maximal line length when calling readline(). _MAXLINE = 65536 _MAXHEADERS = 100 # Header name/value ABNF (http://tools.ietf.org/html/rfc7230#section-3.2) # # VCHAR = %x21-7E # obs-text = %x80-FF # header-field = field-name ":" OWS field-value OWS # field-name = token # field-value = *( field-content / obs-fold ) # field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] # field-vchar = VCHAR / obs-text # # obs-fold = CRLF 1*( SP / HTAB ) # ; obsolete line folding # ; see Section 3.2.4 # token = 1*tchar # # tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" # / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" # / DIGIT / ALPHA # ; any VCHAR, except delimiters # # VCHAR defined in http://tools.ietf.org/html/rfc5234#appendix-B.1 # the patterns for both name and value are more lenient than RFC # definitions to allow for backwards compatibility _is_legal_header_name = re.compile(rb'[^:\s][^:\r\n]*').fullmatch _is_illegal_header_value = re.compile(rb'\n(?![ \t])|\r(?![ \t\n])').search # These characters are not allowed within HTTP URL paths. # See https://tools.ietf.org/html/rfc3986#section-3.3 and the # https://tools.ietf.org/html/rfc3986#appendix-A pchar definition. # Prevents CVE-2019-9740. Includes control characters such as \r\n. # We don't restrict chars above \x7f as putrequest() limits us to ASCII. _contains_disallowed_url_pchar_re = re.compile('[\x00-\x20\x7f]') # Arguably only these _should_ allowed: # _is_allowed_url_pchars_re = re.compile(r"^[/!$&'()*+,;=:@%a-zA-Z0-9._~-]+$") # We are more lenient for assumed real world compatibility purposes. # These characters are not allowed within HTTP method names # to prevent http header injection. _contains_disallowed_method_pchar_re = re.compile('[\x00-\x1f]') # We always set the Content-Length header for these methods because some # servers will otherwise respond with a 411 _METHODS_EXPECTING_BODY = {'PATCH', 'POST', 'PUT'} def _encode(data, name='data'): """Call data.encode("latin-1") but show a better error message.""" try: return data.encode("latin-1") except UnicodeEncodeError as err: raise UnicodeEncodeError( err.encoding, err.object, err.start, err.end, "%s (%.20r) is not valid Latin-1. Use %s.encode('utf-8') " "if you want to send it encoded in UTF-8." % (name.title(), data[err.start:err.end], name)) from None class HTTPMessage(email.message.Message): # XXX The only usage of this method is in # http.server.CGIHTTPRequestHandler. Maybe move the code there so # that it doesn't need to be part of the public API. The API has # never been defined so this could cause backwards compatibility # issues. def getallmatchingheaders(self, name): """Find all header lines matching a given header name. Look through the list of headers and find all lines matching a given header name (and their continuation lines). A list of the lines is returned, without interpretation. If the header does not occur, an empty list is returned. If the header occurs multiple times, all occurrences are returned. Case is not important in the header name. """ name = name.lower() + ':' n = len(name) lst = [] hit = 0 for line in self.keys(): if line[:n].lower() == name: hit = 1 elif not line[:1].isspace(): hit = 0 if hit: lst.append(line) return lst def _read_headers(fp): """Reads potential header lines into a list from a file pointer. Length of line is limited by _MAXLINE, and number of headers is limited by _MAXHEADERS. """ headers = [] while True: line = fp.readline(_MAXLINE + 1) if len(line) > _MAXLINE: raise LineTooLong("header line") headers.append(line) if len(headers) > _MAXHEADERS: raise HTTPException("got more than %d headers" % _MAXHEADERS) if line in (b'\r\n', b'\n', b''): break return headers def parse_headers(fp, _class=HTTPMessage): """Parses only RFC2822 headers from a file pointer. email Parser wants to see strings rather than bytes. But a TextIOWrapper around self.rfile would buffer too many bytes from the stream, bytes which we later need to read as bytes. So we read the correct bytes here, as bytes, for email Parser to parse. """ headers = _read_headers(fp) hstring = b''.join(headers).decode('iso-8859-1') return email.parser.Parser(_class=_class).parsestr(hstring) class HTTPResponse(io.BufferedIOBase): # See RFC 2616 sec 19.6 and RFC 1945 sec 6 for details. # The bytes from the socket object are iso-8859-1 strings. # See RFC 2616 sec 2.2 which notes an exception for MIME-encoded # text following RFC 2047. The basic status line parsing only # accepts iso-8859-1. def __init__(self, sock, debuglevel=0, method=None, url=None): # If the response includes a content-length header, we need to # make sure that the client doesn't read more than the # specified number of bytes. If it does, it will block until # the server times out and closes the connection. This will # happen if a self.fp.read() is done (without a size) whether # self.fp is buffered or not. So, no self.fp.read() by # clients unless they know what they are doing. self.fp = sock.makefile("rb") self.debuglevel = debuglevel self._method = method # The HTTPResponse object is returned via urllib. The clients # of http and urllib expect different attributes for the # headers. headers is used here and supports urllib. msg is # provided as a backwards compatibility layer for http # clients. self.headers = self.msg = None # from the Status-Line of the response self.version = _UNKNOWN # HTTP-Version self.status = _UNKNOWN # Status-Code self.reason = _UNKNOWN # Reason-Phrase self.chunked = _UNKNOWN # is "chunked" being used? self.chunk_left = _UNKNOWN # bytes left to read in current chunk self.length = _UNKNOWN # number of bytes left in response self.will_close = _UNKNOWN # conn will close at end of response def _read_status(self): line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1") if len(line) > _MAXLINE: raise LineTooLong("status line") if self.debuglevel > 0: print("reply:", repr(line)) if not line: # Presumably, the server closed the connection before # sending a valid response. raise RemoteDisconnected("Remote end closed connection without" " response") try: version, status, reason = line.split(None, 2) except ValueError: try: version, status = line.split(None, 1) reason = "" except ValueError: # empty version will cause next test to fail. version = "" if not version.startswith("HTTP/"): self._close_conn() raise BadStatusLine(line) # The status code is a three-digit number try: status = int(status) if status < 100 or status > 999: raise BadStatusLine(line) except ValueError: raise BadStatusLine(line) return version, status, reason def begin(self): if self.headers is not None: # we've already started reading the response return # read until we get a non-100 response while True: version, status, reason = self._read_status() if status != CONTINUE: break # skip the header from the 100 response skipped_headers = _read_headers(self.fp) if self.debuglevel > 0: print("headers:", skipped_headers) del skipped_headers self.code = self.status = status self.reason = reason.strip() if version in ("HTTP/1.0", "HTTP/0.9"): # Some servers might still return "0.9", treat it as 1.0 anyway self.version = 10 elif version.startswith("HTTP/1."): self.version = 11 # use HTTP/1.1 code for HTTP/1.x where x>=1 else: raise UnknownProtocol(version) self.headers = self.msg = parse_headers(self.fp) if self.debuglevel > 0: for hdr, val in self.headers.items(): print("header:", hdr + ":", val) # are we using the chunked-style of transfer encoding? tr_enc = self.headers.get("transfer-encoding") if tr_enc and tr_enc.lower() == "chunked": self.chunked = True self.chunk_left = None else: self.chunked = False # will the connection close at the end of the response? self.will_close = self._check_close() # do we have a Content-Length? # NOTE: RFC 2616, S4.4, #3 says we ignore this if tr_enc is "chunked" self.length = None length = self.headers.get("content-length") if length and not self.chunked: try: self.length = int(length) except ValueError: self.length = None else: if self.length < 0: # ignore nonsensical negative lengths self.length = None else: self.length = None # does the body have a fixed length? (of zero) if (status == NO_CONTENT or status == NOT_MODIFIED or 100 <= status < 200 or # 1xx codes self._method == "HEAD"): self.length = 0 # if the connection remains open, and we aren't using chunked, and # a content-length was not provided, then assume that the connection # WILL close. if (not self.will_close and not self.chunked and self.length is None): self.will_close = True def _check_close(self): conn = self.headers.get("connection") if self.version == 11: # An HTTP/1.1 proxy is assumed to stay open unless # explicitly closed. if conn and "close" in conn.lower(): return True return False # Some HTTP/1.0 implementations have support for persistent # connections, using rules different than HTTP/1.1. # For older HTTP, Keep-Alive indicates persistent connection. if self.headers.get("keep-alive"): return False # At least Akamai returns a "Connection: Keep-Alive" header, # which was supposed to be sent by the client. if conn and "keep-alive" in conn.lower(): return False # Proxy-Connection is a netscape hack. pconn = self.headers.get("proxy-connection") if pconn and "keep-alive" in pconn.lower(): return False # otherwise, assume it will close return True def _close_conn(self): fp = self.fp self.fp = None fp.close() def close(self): try: super().close() # set "closed" flag finally: if self.fp: self._close_conn() # These implementations are for the benefit of io.BufferedReader. # XXX This class should probably be revised to act more like # the "raw stream" that BufferedReader expects. def flush(self): super().flush() if self.fp: self.fp.flush() def readable(self): """Always returns True""" return True # End of "raw stream" methods def isclosed(self): """True if the connection is closed.""" # NOTE: it is possible that we will not ever call self.close(). This # case occurs when will_close is TRUE, length is None, and we # read up to the last byte, but NOT past it. # # IMPLIES: if will_close is FALSE, then self.close() will ALWAYS be # called, meaning self.isclosed() is meaningful. return self.fp is None def read(self, amt=None): if self.fp is None: return b"" if self._method == "HEAD": self._close_conn() return b"" if self.chunked: return self._read_chunked(amt) if amt is not None: if self.length is not None and amt > self.length: # clip the read to the "end of response" amt = self.length s = self.fp.read(amt) if not s and amt: # Ideally, we would raise IncompleteRead if the content-length # wasn't satisfied, but it might break compatibility. self._close_conn() elif self.length is not None: self.length -= len(s) if not self.length: self._close_conn() return s else: # Amount is not given (unbounded read) so we must check self.length if self.length is None: s = self.fp.read() else: try: s = self._safe_read(self.length) except IncompleteRead: self._close_conn() raise self.length = 0 self._close_conn() # we read everything return s def readinto(self, b): """Read up to len(b) bytes into bytearray b and return the number of bytes read. """ if self.fp is None: return 0 if self._method == "HEAD": self._close_conn() return 0 if self.chunked: return self._readinto_chunked(b) if self.length is not None: if len(b) > self.length: # clip the read to the "end of response" b = memoryview(b)[0:self.length] # we do not use _safe_read() here because this may be a .will_close # connection, and the user is reading more bytes than will be provided # (for example, reading in 1k chunks) n = self.fp.readinto(b) if not n and b: # Ideally, we would raise IncompleteRead if the content-length # wasn't satisfied, but it might break compatibility. self._close_conn() elif self.length is not None: self.length -= n if not self.length: self._close_conn() return n def _read_next_chunk_size(self): # Read the next chunk size from the file line = self.fp.readline(_MAXLINE + 1) if len(line) > _MAXLINE: raise LineTooLong("chunk size") i = line.find(b";") if i >= 0: line = line[:i] # strip chunk-extensions try: return int(line, 16) except ValueError: # close the connection as protocol synchronisation is # probably lost self._close_conn() raise def _read_and_discard_trailer(self): # read and discard trailer up to the CRLF terminator ### note: we shouldn't have any trailers! while True: line = self.fp.readline(_MAXLINE + 1) if len(line) > _MAXLINE: raise LineTooLong("trailer line") if not line: # a vanishingly small number of sites EOF without # sending the trailer break if line in (b'\r\n', b'\n', b''): break def _get_chunk_left(self): # return self.chunk_left, reading a new chunk if necessary. # chunk_left == 0: at the end of the current chunk, need to close it # chunk_left == None: No current chunk, should read next. # This function returns non-zero or None if the last chunk has # been read. chunk_left = self.chunk_left if not chunk_left: # Can be 0 or None if chunk_left is not None: # We are at the end of chunk, discard chunk end self._safe_read(2) # toss the CRLF at the end of the chunk try: chunk_left = self._read_next_chunk_size() except ValueError: raise IncompleteRead(b'') if chunk_left == 0: # last chunk: 1*("0") [ chunk-extension ] CRLF self._read_and_discard_trailer() # we read everything; close the "file" self._close_conn() chunk_left = None self.chunk_left = chunk_left return chunk_left def _read_chunked(self, amt=None): assert self.chunked != _UNKNOWN value = [] try: while True: chunk_left = self._get_chunk_left() if chunk_left is None: break if amt is not None and amt <= chunk_left: value.append(self._safe_read(amt)) self.chunk_left = chunk_left - amt break value.append(self._safe_read(chunk_left)) if amt is not None: amt -= chunk_left self.chunk_left = 0 return b''.join(value) except IncompleteRead as exc: raise IncompleteRead(b''.join(value)) from exc def _readinto_chunked(self, b): assert self.chunked != _UNKNOWN total_bytes = 0 mvb = memoryview(b) try: while True: chunk_left = self._get_chunk_left() if chunk_left is None: return total_bytes if len(mvb) <= chunk_left: n = self._safe_readinto(mvb) self.chunk_left = chunk_left - n return total_bytes + n temp_mvb = mvb[:chunk_left] n = self._safe_readinto(temp_mvb) mvb = mvb[n:] total_bytes += n self.chunk_left = 0 except IncompleteRead: raise IncompleteRead(bytes(b[0:total_bytes])) def _safe_read(self, amt): """Read the number of bytes requested. This function should be used when <amt> bytes "should" be present for reading. If the bytes are truly not available (due to EOF), then the IncompleteRead exception can be used to detect the problem. """ data = self.fp.read(amt) if len(data) < amt: raise IncompleteRead(data, amt-len(data)) return data def _safe_readinto(self, b): """Same as _safe_read, but for reading into a buffer.""" amt = len(b) n = self.fp.readinto(b) if n < amt: raise IncompleteRead(bytes(b[:n]), amt-n) return n def read1(self, n=-1): """Read with at most one underlying system call. If at least one byte is buffered, return that instead. """ if self.fp is None or self._method == "HEAD": return b"" if self.chunked: return self._read1_chunked(n) if self.length is not None and (n < 0 or n > self.length): n = self.length result = self.fp.read1(n) if not result and n: self._close_conn() elif self.length is not None: self.length -= len(result) return result def peek(self, n=-1): # Having this enables IOBase.readline() to read more than one # byte at a time if self.fp is None or self._method == "HEAD": return b"" if self.chunked: return self._peek_chunked(n) return self.fp.peek(n) def readline(self, limit=-1): if self.fp is None or self._method == "HEAD": return b"" if self.chunked: # Fallback to IOBase readline which uses peek() and read() return super().readline(limit) if self.length is not None and (limit < 0 or limit > self.length): limit = self.length result = self.fp.readline(limit) if not result and limit: self._close_conn() elif self.length is not None: self.length -= len(result) return result def _read1_chunked(self, n): # Strictly speaking, _get_chunk_left() may cause more than one read, # but that is ok, since that is to satisfy the chunked protocol. chunk_left = self._get_chunk_left() if chunk_left is None or n == 0: return b'' if not (0 <= n <= chunk_left): n = chunk_left # if n is negative or larger than chunk_left read = self.fp.read1(n) self.chunk_left -= len(read) if not read: raise IncompleteRead(b"") return read def _peek_chunked(self, n): # Strictly speaking, _get_chunk_left() may cause more than one read, # but that is ok, since that is to satisfy the chunked protocol. try: chunk_left = self._get_chunk_left() except IncompleteRead: return b'' # peek doesn't worry about protocol if chunk_left is None: return b'' # eof # peek is allowed to return more than requested. Just request the # entire chunk, and truncate what we get. return self.fp.peek(chunk_left)[:chunk_left] def fileno(self): return self.fp.fileno() def getheader(self, name, default=None): '''Returns the value of the header matching *name*. If there are multiple matching headers, the values are combined into a single string separated by commas and spaces. If no matching header is found, returns *default* or None if the *default* is not specified. If the headers are unknown, raises http.client.ResponseNotReady. ''' if self.headers is None: raise ResponseNotReady() headers = self.headers.get_all(name) or default if isinstance(headers, str) or not hasattr(headers, '__iter__'): return headers else: return ', '.join(headers) def getheaders(self): """Return list of (header, value) tuples.""" if self.headers is None: raise ResponseNotReady() return list(self.headers.items()) # We override IOBase.__iter__ so that it doesn't check for closed-ness def __iter__(self): return self # For compatibility with old-style urllib responses. def info(self): '''Returns an instance of the class mimetools.Message containing meta-information associated with the URL. When the method is HTTP, these headers are those returned by the server at the head of the retrieved HTML page (including Content-Length and Content-Type). When the method is FTP, a Content-Length header will be present if (as is now usual) the server passed back a file length in response to the FTP retrieval request. A Content-Type header will be present if the MIME type can be guessed. When the method is local-file, returned headers will include a Date representing the file's last-modified time, a Content-Length giving file size, and a Content-Type containing a guess at the file's type. See also the description of the mimetools module. ''' return self.headers def geturl(self): '''Return the real URL of the page. In some cases, the HTTP server redirects a client to another URL. The urlopen() function handles this transparently, but in some cases the caller needs to know which URL the client was redirected to. The geturl() method can be used to get at this redirected URL. ''' return self.url def getcode(self): '''Return the HTTP status code that was sent with the response, or None if the URL is not an HTTP URL. ''' return self.status class HTTPConnection: _http_vsn = 11 _http_vsn_str = 'HTTP/1.1' response_class = HTTPResponse default_port = HTTP_PORT auto_open = 1 debuglevel = 0 @staticmethod def _is_textIO(stream): """Test whether a file-like object is a text or a binary stream. """ return isinstance(stream, io.TextIOBase) @staticmethod def _get_content_length(body, method): """Get the content-length based on the body. If the body is None, we set Content-Length: 0 for methods that expect a body (RFC 7230, Section 3.3.2). We also set the Content-Length for any method if the body is a str or bytes-like object and not a file. """ if body is None: # do an explicit check for not None here to distinguish # between unset and set but empty if method.upper() in _METHODS_EXPECTING_BODY: return 0 else: return None if hasattr(body, 'read'): # file-like object. return None try: # does it implement the buffer protocol (bytes, bytearray, array)? mv = memoryview(body) return mv.nbytes except TypeError: pass if isinstance(body, str): return len(body) return None def __init__(self, host, port=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None, blocksize=8192): self.timeout = timeout self.source_address = source_address self.blocksize = blocksize self.sock = None self._buffer = [] self.__response = None self.__state = _CS_IDLE self._method = None self._tunnel_host = None self._tunnel_port = None self._tunnel_headers = {} (self.host, self.port) = self._get_hostport(host, port) self._validate_host(self.host) # This is stored as an instance variable to allow unit # tests to replace it with a suitable mockup self._create_connection = socket.create_connection def set_tunnel(self, host, port=None, headers=None): """Set up host and port for HTTP CONNECT tunnelling. In a connection that uses HTTP CONNECT tunneling, the host passed to the constructor is used as a proxy server that relays all communication to the endpoint passed to `set_tunnel`. This done by sending an HTTP CONNECT request to the proxy server when the connection is established. This method must be called before the HTTP connection has been established. The headers argument should be a mapping of extra HTTP headers to send with the CONNECT request. """ if self.sock: raise RuntimeError("Can't set up tunnel for established connection") self._tunnel_host, self._tunnel_port = self._get_hostport(host, port) if headers: self._tunnel_headers = headers else: self._tunnel_headers.clear() def _get_hostport(self, host, port): if port is None: i = host.rfind(':') j = host.rfind(']') # ipv6 addresses have [...] if i > j: try: port = int(host[i+1:]) except ValueError: if host[i+1:] == "": # http://foo.com:/ == http://foo.com/ port = self.default_port else: raise InvalidURL("nonnumeric port: '%s'" % host[i+1:]) host = host[:i] else: port = self.default_port if host and host[0] == '[' and host[-1] == ']': host = host[1:-1] return (host, port) def set_debuglevel(self, level): self.debuglevel = level def _tunnel(self): connect = b"CONNECT %s:%d HTTP/1.0\r\n" % ( self._tunnel_host.encode("ascii"), self._tunnel_port) headers = [connect] for header, value in self._tunnel_headers.items(): headers.append(f"{header}: {value}\r\n".encode("latin-1")) headers.append(b"\r\n") # Making a single send() call instead of one per line encourages # the host OS to use a more optimal packet size instead of # potentially emitting a series of small packets. self.send(b"".join(headers)) del headers response = self.response_class(self.sock, method=self._method) (version, code, message) = response._read_status() if code != http.HTTPStatus.OK: self.close() raise OSError(f"Tunnel connection failed: {code} {message.strip()}") while True: line = response.fp.readline(_MAXLINE + 1) if len(line) > _MAXLINE: raise LineTooLong("header line") if not line: # for sites which EOF without sending a trailer break if line in (b'\r\n', b'\n', b''): break if self.debuglevel > 0: print('header:', line.decode()) def connect(self): """Connect to the host and port specified in __init__.""" sys.audit("http.client.connect", self, self.host, self.port) self.sock = self._create_connection( (self.host,self.port), self.timeout, self.source_address) # Might fail in OSs that don't implement TCP_NODELAY try: self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) except OSError as e: if e.errno != errno.ENOPROTOOPT: raise if self._tunnel_host: self._tunnel() def close(self): """Close the connection to the HTTP server.""" self.__state = _CS_IDLE try: sock = self.sock if sock: self.sock = None sock.close() # close it manually... there may be other refs finally: response = self.__response if response: self.__response = None response.close() def send(self, data): """Send `data' to the server. ``data`` can be a string object, a bytes object, an array object, a file-like object that supports a .read() method, or an iterable object. """ if self.sock is None: if self.auto_open: self.connect() else: raise NotConnected() if self.debuglevel > 0: print("send:", repr(data)) if hasattr(data, "read") : if self.debuglevel > 0: print("sendIng a read()able") encode = self._is_textIO(data) if encode and self.debuglevel > 0: print("encoding file using iso-8859-1") while 1: datablock = data.read(self.blocksize) if not datablock: break if encode: datablock = datablock.encode("iso-8859-1") sys.audit("http.client.send", self, datablock) self.sock.sendall(datablock) return sys.audit("http.client.send", self, data) try: self.sock.sendall(data) except TypeError: if isinstance(data, collections.abc.Iterable): for d in data: self.sock.sendall(d) else: raise TypeError("data should be a bytes-like object " "or an iterable, got %r" % type(data)) def _output(self, s): """Add a line of output to the current request buffer. Assumes that the line does *not* end with \\r\\n. """ self._buffer.append(s) def _read_readable(self, readable): if self.debuglevel > 0: print("sendIng a read()able") encode = self._is_textIO(readable) if encode and self.debuglevel > 0: print("encoding file using iso-8859-1") while True: datablock = readable.read(self.blocksize) if not datablock: break if encode: datablock = datablock.encode("iso-8859-1") yield datablock def _send_output(self, message_body=None, encode_chunked=False): """Send the currently buffered request and clear the buffer. Appends an extra \\r\\n to the buffer. A message_body may be specified, to be appended to the request. """ self._buffer.extend((b"", b"")) msg = b"\r\n".join(self._buffer) del self._buffer[:] self.send(msg) if message_body is not None: # create a consistent interface to message_body if hasattr(message_body, 'read'): # Let file-like take precedence over byte-like. This # is needed to allow the current position of mmap'ed # files to be taken into account. chunks = self._read_readable(message_body) else: try: # this is solely to check to see if message_body # implements the buffer API. it /would/ be easier # to capture if PyObject_CheckBuffer was exposed # to Python. memoryview(message_body) except TypeError: try: chunks = iter(message_body) except TypeError: raise TypeError("message_body should be a bytes-like " "object or an iterable, got %r" % type(message_body)) else: # the object implements the buffer interface and # can be passed directly into socket methods chunks = (message_body,) for chunk in chunks: if not chunk: if self.debuglevel > 0: print('Zero length chunk ignored') continue if encode_chunked and self._http_vsn == 11: # chunked encoding chunk = f'{len(chunk):X}\r\n'.encode('ascii') + chunk \ + b'\r\n' self.send(chunk) if encode_chunked and self._http_vsn == 11: # end chunked transfer self.send(b'0\r\n\r\n') def putrequest(self, method, url, skip_host=False, skip_accept_encoding=False): """Send a request to the server. `method' specifies an HTTP request method, e.g. 'GET'. `url' specifies the object being requested, e.g. '/index.html'. `skip_host' if True does not add automatically a 'Host:' header `skip_accept_encoding' if True does not add automatically an 'Accept-Encoding:' header """ # if a prior response has been completed, then forget about it. if self.__response and self.__response.isclosed(): self.__response = None # in certain cases, we cannot issue another request on this connection. # this occurs when: # 1) we are in the process of sending a request. (_CS_REQ_STARTED) # 2) a response to a previous request has signalled that it is going # to close the connection upon completion. # 3) the headers for the previous response have not been read, thus # we cannot determine whether point (2) is true. (_CS_REQ_SENT) # # if there is no prior response, then we can request at will. # # if point (2) is true, then we will have passed the socket to the # response (effectively meaning, "there is no prior response"), and # will open a new one when a new request is made. # # Note: if a prior response exists, then we *can* start a new request. # We are not allowed to begin fetching the response to this new # request, however, until that prior response is complete. # if self.__state == _CS_IDLE: self.__state = _CS_REQ_STARTED else: raise CannotSendRequest(self.__state) self._validate_method(method) # Save the method for use later in the response phase self._method = method url = url or '/' self._validate_path(url) request = '%s %s %s' % (method, url, self._http_vsn_str) self._output(self._encode_request(request)) if self._http_vsn == 11: # Issue some standard headers for better HTTP/1.1 compliance if not skip_host: # this header is issued *only* for HTTP/1.1 # connections. more specifically, this means it is # only issued when the client uses the new # HTTPConnection() class. backwards-compat clients # will be using HTTP/1.0 and those clients may be # issuing this header themselves. we should NOT issue # it twice; some web servers (such as Apache) barf # when they see two Host: headers # If we need a non-standard port,include it in the # header. If the request is going through a proxy, # but the host of the actual URL, not the host of the # proxy. netloc = '' if url.startswith('http'): nil, netloc, nil, nil, nil = urlsplit(url) if netloc: try: netloc_enc = netloc.encode("ascii") except UnicodeEncodeError: netloc_enc = netloc.encode("idna") self.putheader('Host', netloc_enc) else: if self._tunnel_host: host = self._tunnel_host port = self._tunnel_port else: host = self.host port = self.port try: host_enc = host.encode("ascii") except UnicodeEncodeError: host_enc = host.encode("idna") # As per RFC 273, IPv6 address should be wrapped with [] # when used as Host header if host.find(':') >= 0: host_enc = b'[' + host_enc + b']' if port == self.default_port: self.putheader('Host', host_enc) else: host_enc = host_enc.decode("ascii") self.putheader('Host', "%s:%s" % (host_enc, port)) # note: we are assuming that clients will not attempt to set these # headers since *this* library must deal with the # consequences. this also means that when the supporting # libraries are updated to recognize other forms, then this # code should be changed (removed or updated). # we only want a Content-Encoding of "identity" since we don't # support encodings such as x-gzip or x-deflate. if not skip_accept_encoding: self.putheader('Accept-Encoding', 'identity') # we can accept "chunked" Transfer-Encodings, but no others # NOTE: no TE header implies *only* "chunked" #self.putheader('TE', 'chunked') # if TE is supplied in the header, then it must appear in a # Connection header. #self.putheader('Connection', 'TE') else: # For HTTP/1.0, the server will assume "not chunked" pass def _encode_request(self, request): # ASCII also helps prevent CVE-2019-9740. return request.encode('ascii') def _validate_method(self, method): """Validate a method name for putrequest.""" # prevent http header injection match = _contains_disallowed_method_pchar_re.search(method) if match: raise ValueError( f"method can't contain control characters. {method!r} " f"(found at least {match.group()!r})") def _validate_path(self, url): """Validate a url for putrequest.""" # Prevent CVE-2019-9740. match = _contains_disallowed_url_pchar_re.search(url) if match: raise InvalidURL(f"URL can't contain control characters. {url!r} " f"(found at least {match.group()!r})") def _validate_host(self, host): """Validate a host so it doesn't contain control characters.""" # Prevent CVE-2019-18348. match = _contains_disallowed_url_pchar_re.search(host) if match: raise InvalidURL(f"URL can't contain control characters. {host!r} " f"(found at least {match.group()!r})") def putheader(self, header, *values): """Send a request header line to the server. For example: h.putheader('Accept', 'text/html') """ if self.__state != _CS_REQ_STARTED: raise CannotSendHeader() if hasattr(header, 'encode'): header = header.encode('ascii') if not _is_legal_header_name(header): raise ValueError('Invalid header name %r' % (header,)) values = list(values) for i, one_value in enumerate(values): if hasattr(one_value, 'encode'): values[i] = one_value.encode('latin-1') elif isinstance(one_value, int): values[i] = str(one_value).encode('ascii') if _is_illegal_header_value(values[i]): raise ValueError('Invalid header value %r' % (values[i],)) value = b'\r\n\t'.join(values) header = header + b': ' + value self._output(header) def endheaders(self, message_body=None, *, encode_chunked=False): """Indicate that the last header line has been sent to the server. This method sends the request to the server. The optional message_body argument can be used to pass a message body associated with the request. """ if self.__state == _CS_REQ_STARTED: self.__state = _CS_REQ_SENT else: raise CannotSendHeader() self._send_output(message_body, encode_chunked=encode_chunked) def request(self, method, url, body=None, headers={}, *, encode_chunked=False): """Send a complete request to the server.""" self._send_request(method, url, body, headers, encode_chunked) def _send_request(self, method, url, body, headers, encode_chunked): # Honor explicitly requested Host: and Accept-Encoding: headers. header_names = frozenset(k.lower() for k in headers) skips = {} if 'host' in header_names: skips['skip_host'] = 1 if 'accept-encoding' in header_names: skips['skip_accept_encoding'] = 1 self.putrequest(method, url, **skips) # chunked encoding will happen if HTTP/1.1 is used and either # the caller passes encode_chunked=True or the following # conditions hold: # 1. content-length has not been explicitly set # 2. the body is a file or iterable, but not a str or bytes-like # 3. Transfer-Encoding has NOT been explicitly set by the caller if 'content-length' not in header_names: # only chunk body if not explicitly set for backwards # compatibility, assuming the client code is already handling the # chunking if 'transfer-encoding' not in header_names: # if content-length cannot be automatically determined, fall # back to chunked encoding encode_chunked = False content_length = self._get_content_length(body, method) if content_length is None: if body is not None: if self.debuglevel > 0: print('Unable to determine size of %r' % body) encode_chunked = True self.putheader('Transfer-Encoding', 'chunked') else: self.putheader('Content-Length', str(content_length)) else: encode_chunked = False for hdr, value in headers.items(): self.putheader(hdr, value) if isinstance(body, str): # RFC 2616 Section 3.7.1 says that text default has a # default charset of iso-8859-1. body = _encode(body, 'body') self.endheaders(body, encode_chunked=encode_chunked) def getresponse(self): """Get the response from the server. If the HTTPConnection is in the correct state, returns an instance of HTTPResponse or of whatever object is returned by the response_class variable. If a request has not been sent or if a previous response has not be handled, ResponseNotReady is raised. If the HTTP response indicates that the connection should be closed, then it will be closed before the response is returned. When the connection is closed, the underlying socket is closed. """ # if a prior response has been completed, then forget about it. if self.__response and self.__response.isclosed(): self.__response = None # if a prior response exists, then it must be completed (otherwise, we # cannot read this response's header to determine the connection-close # behavior) # # note: if a prior response existed, but was connection-close, then the # socket and response were made independent of this HTTPConnection # object since a new request requires that we open a whole new # connection # # this means the prior response had one of two states: # 1) will_close: this connection was reset and the prior socket and # response operate independently # 2) persistent: the response was retained and we await its # isclosed() status to become true. # if self.__state != _CS_REQ_SENT or self.__response: raise ResponseNotReady(self.__state) if self.debuglevel > 0: response = self.response_class(self.sock, self.debuglevel, method=self._method) else: response = self.response_class(self.sock, method=self._method) try: try: response.begin() except ConnectionError: self.close() raise assert response.will_close != _UNKNOWN self.__state = _CS_IDLE if response.will_close: # this effectively passes the connection to the response self.close() else: # remember this, so we can tell when it is complete self.__response = response return response except: response.close() raise try: import ssl except ImportError: pass else: class HTTPSConnection(HTTPConnection): "This class allows communication via SSL." default_port = HTTPS_PORT # XXX Should key_file and cert_file be deprecated in favour of context? def __init__(self, host, port=None, key_file=None, cert_file=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None, *, context=None, check_hostname=None, blocksize=8192): super(HTTPSConnection, self).__init__(host, port, timeout, source_address, blocksize=blocksize) if (key_file is not None or cert_file is not None or check_hostname is not None): import warnings warnings.warn("key_file, cert_file and check_hostname are " "deprecated, use a custom context instead.", DeprecationWarning, 2) self.key_file = key_file self.cert_file = cert_file if context is None: context = ssl._create_default_https_context() # send ALPN extension to indicate HTTP/1.1 protocol if self._http_vsn == 11: context.set_alpn_protocols(['http/1.1']) # enable PHA for TLS 1.3 connections if available if context.post_handshake_auth is not None: context.post_handshake_auth = True will_verify = context.verify_mode != ssl.CERT_NONE if check_hostname is None: check_hostname = context.check_hostname if check_hostname and not will_verify: raise ValueError("check_hostname needs a SSL context with " "either CERT_OPTIONAL or CERT_REQUIRED") if key_file or cert_file: context.load_cert_chain(cert_file, key_file) # cert and key file means the user wants to authenticate. # enable TLS 1.3 PHA implicitly even for custom contexts. if context.post_handshake_auth is not None: context.post_handshake_auth = True self._context = context if check_hostname is not None: self._context.check_hostname = check_hostname def connect(self): "Connect to a host on a given (SSL) port." super().connect() if self._tunnel_host: server_hostname = self._tunnel_host else: server_hostname = self.host self.sock = self._context.wrap_socket(self.sock, server_hostname=server_hostname) __all__.append("HTTPSConnection") class HTTPException(Exception): # Subclasses that define an __init__ must call Exception.__init__ # or define self.args. Otherwise, str() will fail. pass class NotConnected(HTTPException): pass class InvalidURL(HTTPException): pass class UnknownProtocol(HTTPException): def __init__(self, version): self.args = version, self.version = version class UnknownTransferEncoding(HTTPException): pass class UnimplementedFileMode(HTTPException): pass class IncompleteRead(HTTPException): def __init__(self, partial, expected=None): self.args = partial, self.partial = partial self.expected = expected def __repr__(self): if self.expected is not None: e = ', %i more expected' % self.expected else: e = '' return '%s(%i bytes read%s)' % (self.__class__.__name__, len(self.partial), e) __str__ = object.__str__ class ImproperConnectionState(HTTPException): pass class CannotSendRequest(ImproperConnectionState): pass class CannotSendHeader(ImproperConnectionState): pass class ResponseNotReady(ImproperConnectionState): pass class BadStatusLine(HTTPException): def __init__(self, line): if not line: line = repr(line) self.args = line, self.line = line class LineTooLong(HTTPException): def __init__(self, line_type): HTTPException.__init__(self, "got more than %d bytes when reading %s" % (_MAXLINE, line_type)) class RemoteDisconnected(ConnectionResetError, BadStatusLine): def __init__(self, *pos, **kw): BadStatusLine.__init__(self, "") ConnectionResetError.__init__(self, *pos, **kw) # for backwards compatibility error = HTTPException 解析这些代码 怎么联接这个服务器
06-19
<think>好的,我现在要解决的问题是解释错误信息“attempted to access an unnamed file past its end”的含义。首先,我需要理解每个部分的关键词。 “attempted to access”意味着程序试图进行某种文件操作,比如读取或写入。“unnamed file”可能指的是没有具体文件名或临时创建的文件,比如内存中的文件或者未保存的临时文件。“past its end”应该是指访问的位置超过了文件的末尾,比如尝试读取文件结尾之后的数据。 接下来,我需要考虑可能的场景。比如,当程序用类似于C的fread函数读取文件时,如果文件指针已经到达末尾,继续读取就会触发这个错误。或者在处理流数据时,如果流已经关闭但还尝试读取,也可能出现这种情况。 另外,可能涉及到编程语言的特定库或框架。例如,某些低级语言如C/C++直接操作文件指针,容易因未检查文件边界而出错。高级语言如Python可能有更友好的错误提示,但底层逻辑类似。 需要区分其他类似错误,比如“file not found”是文件不存在,而这里的错误是访问越界。用户可能混淆这两者,所以需要明确说明差异。 还应考虑用户可能的操作场景,比如开发过程中文件处理代码有误,或者使用了临时文件但未正确管理其生命周期。例如,在循环中反复读取文件但未重置指针,导致后续读取越界。 最后,应该给出解决方法,比如检查文件指针位置,确保读取前文件未结束,使用feof或类似函数检测结尾,或者检查文件是否被意外关闭。 总结步骤:解释每个术语,分析常见原因,举例说明,提供解决方案,并对比其他错误以避免混淆。</think>“attempted to access an unnamed file past its end” 是一个与文件操作相关的错误提示,通常出现在编程中。以下是逐步分析: --- ### **1. 错误分解** - **"unnamed file"** 指程序正在操作的文件**未显式命名**,可能是: - 临时创建的内存文件(未保存到磁盘) - 通过文件描述符(File Descriptor)或句柄(Handle)直接操作的文件 - 某些编程框架自动生成的匿名文件 - **"past its end"** 表示程序试图**访问超出文件实际结尾的位置**,例如: - 读取超过文件末尾的数据 - 写入时指针意外越界 --- ### **2. 常见场景** #### **场景1:文件读取越界** 当使用类似以下代码时可能触发: ```c FILE *fp = tmpfile(); // 创建临时无名文件 fseek(fp, 100, SEEK_END); // 将指针移动到文件结尾后100字节 fread(buffer, 1, 10, fp); // 试图读取不存在的区域 ``` **原因**:未检查文件指针位置是否合法。 #### **场景2:文件流状态异常** 若文件已关闭但仍在操作: ```python import tempfile f = tempfile.TemporaryFile() f.close() f.read() # 操作已关闭的临时文件 ``` **结果**:Python会报错,但底层可能提示类似信息。 --- ### **3. 解决方法** - **检查文件指针位置** 使用 `ftell()`(C语言)或 `file.tell()`(Python)确认当前操作位置。 - **验证文件结尾** 读取前用 `feof()`(C语言)或捕获 `EOFError`(Python)判断是否到达结尾。 - **修复逻辑错误** 确保循环读取时重置指针(例如 `rewind()` 或 `seek(0)`)。 - **检查文件生命周期** 确保文件未提前关闭或删除。 --- ### **4. 对比类似错误** | 错误类型 | 关键区别 | |---------|----------| | `File not found` | 文件路径错误或未创建 | | `Permission denied` | 无操作权限 | | **本错误** | **文件存在但访问越界** | --- ### **5. 总结** 该错误的核心是**对无名文件进行了越界操作**,需检查: 1. 文件指针位置 2. 文件是否已关闭 3. 读取/写入逻辑是否正确 如果是调试代码,建议逐步输出文件指针位置和文件大小以定位问题。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值